{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "2778b91a-6e7e-47ec-8f7a-5b813ef2e69f",
   "metadata": {},
   "source": [
    "# 任务一：数据集角度分析"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "73ba5625-2099-49a5-bd92-b8b96df8f973",
   "metadata": {},
   "source": [
    "## 数据摘要与数据集基本信息"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "b9287397-4435-453f-b1d5-1d8afe8473e5",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "401dc966-88ed-453d-9932-99d3be87c192",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(12256906, 5)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Index(['user_id', 'item_id', 'behavior_type', 'item_category', 'time'], dtype='object')"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data = pd.read_csv('./data/user_action.csv')\n",
    "data.head()\n",
    "print(data.shape)\n",
    "data.columns "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12997869-2572-4d92-abc4-ff1d1adabf4f",
   "metadata": {},
   "source": [
    "### 读写优化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "b1bc61b5-47f9-4b87-83e2-139b082f27ce",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(100000, 5)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dataframe = pd.read_csv('./data/user_action.csv',\n",
    "                       engine='c',   #使用python引擎\n",
    "                       encoding='utf-8',\n",
    "                       chunksize=100000,   #设置数据快\n",
    "                       iterator=True,    #使用迭代器\n",
    "                       )\n",
    "data = dataframe.get_chunk(100000)\n",
    "data.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "73a2a16d-6346-4d64-a88e-a6424f6fe64d",
   "metadata": {},
   "source": [
    "- chunksize=100000参数，分块读取，Pandas会将文件夹分成大小为100000行的数据块，可以有效管理内存的使用\n",
    "- 特别是当处理非常大的文件时，可以避免一次性将整个文件加载到内存中，从而减少内存溢出的风险\n",
    "- 迭代器，如果启用，他将允许你使用迭代器来逐块处理数据，在处理大数据时非常有用"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "628dea31-74af-46fe-b8c7-a0549e3935a3",
   "metadata": {},
   "source": [
    "### 数据基本信息\n",
    "- 检测数据集大小，使用DataFrame的shape属性获取数据集的大小，即行数和列数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d9153f02-b918-44b6-b385-51ad3f3100d7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "数据集大小：100000行，5列\n",
      "数据集大小：100000行，5列\n"
     ]
    }
   ],
   "source": [
    "rows, cols = data.shape\n",
    "print(f\"数据集大小：{rows}行，{cols}列\")\n",
    "print(\"数据集大小：{}行，{}列\".format(rows,cols))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a8fcea18-d6c6-4883-a827-bc9b7e6f2ad5",
   "metadata": {},
   "source": [
    "- 查看数据集的信息，使用DataFrame的info方法，包括列名，非空值数量以及每列的数据类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "a3134b3a-816d-477d-b1c3-de016def1f59",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "RangeIndex: 100000 entries, 0 to 99999\n",
      "Data columns (total 5 columns):\n",
      " #   Column         Non-Null Count   Dtype \n",
      "---  ------         --------------   ----- \n",
      " 0   user_id        100000 non-null  int64 \n",
      " 1   item_id        100000 non-null  int64 \n",
      " 2   behavior_type  100000 non-null  int64 \n",
      " 3   item_category  100000 non-null  int64 \n",
      " 4   time           100000 non-null  object\n",
      "dtypes: int64(4), object(1)\n",
      "memory usage: 3.8+ MB\n"
     ]
    }
   ],
   "source": [
    "data.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "037b3184-2b97-4167-9d25-28230673c631",
   "metadata": {},
   "source": [
    "### 数据集的统计信息"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "d17663f3-2c66-4c31-968d-fd5f5ac052e9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "count                        100000\n",
       "mean     2014-12-04 08:17:35.016000\n",
       "min             2014-11-18 00:00:00\n",
       "25%             2014-11-26 20:00:00\n",
       "50%             2014-12-04 18:00:00\n",
       "75%             2014-12-12 01:00:00\n",
       "max             2014-12-18 23:00:00\n",
       "Name: time, dtype: object"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#统计用户的数量\n",
    "data['user_id'].nunique()\n",
    "\n",
    "#统计商品数量\n",
    "data['item_id'].nunique()\n",
    "\n",
    "#商品类型统计，可以通过可视化手段，计算出Top5分类商品\n",
    "data['item_category'].nunique()\n",
    "\n",
    "#用户行为统计\n",
    "dicts = {1:'浏览',2:'收藏',3:'加购物车',4:'购买'}\n",
    "data['behavior_type'].value_counts().reset_index().values.tolist()\n",
    "\n",
    "#数据集的时间跨度\n",
    "pd.to_datetime(data['time'],format='%Y-%m-%d %H').describe()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "912c32bb-7be3-4137-9eeb-1ad9f9d56dfc",
   "metadata": {},
   "source": [
    "## 数据清洗"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f2ac04d1-748e-4209-8456-f0ee77910191",
   "metadata": {},
   "source": [
    "### 查看缺失值\n",
    "- 目标：识别数据集中是否存在缺失值，特别是在关键字段\n",
    "- 理由：缺失值可能影响数据分析的准确性，确保数据完整性是进行有效分析的前提"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d5b60213-4bcb-4680-9853-7d6797d37316",
   "metadata": {},
   "source": [
    "### 检查数据集中是否存在缺失值或异常值\n",
    "- 检查缺失值\n",
    "  - 使用DataFrame的isnull()方法检查每个单元格是否为缺失值(NaN或None)\n",
    "  - 使用DataFrame的sum()方法对每列缺失值的数量进行求和\n",
    "  - 使用DataFrame的isnull().any()方法检查每列是否存在缺失值\n",
    "  - 使用DataFrame的isnull().sum()方法计算每列缺失值的数量\n",
    "  - 使用missingno模块检测缺失值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "c98674e1-e2a7-4576-bccf-793aff08f763",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "user_id          0\n",
       "item_id          0\n",
       "behavior_type    0\n",
       "item_category    0\n",
       "time             0\n",
       "dtype: int64"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.isna().sum()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d48747cd-2bad-4de2-8d6c-a1906e9c4d2f",
   "metadata": {},
   "source": [
    "### 识别异常值\n",
    "- 目标：检查数据中是否存在不合理的值或异常情况\n",
    "- 理由：异常值可能导致分析结果失真，识别和处理异常值有助于提高结果的可信度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "73c8b52a-d583-4911-9e7a-9cfa87f96341",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user_id</th>\n",
       "      <th>item_id</th>\n",
       "      <th>behavior_type</th>\n",
       "      <th>item_category</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>count</th>\n",
       "      <td>1.000000e+05</td>\n",
       "      <td>1.000000e+05</td>\n",
       "      <td>100000.000000</td>\n",
       "      <td>100000.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>mean</th>\n",
       "      <td>7.038601e+07</td>\n",
       "      <td>2.018416e+08</td>\n",
       "      <td>1.100130</td>\n",
       "      <td>6837.302220</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>std</th>\n",
       "      <td>4.260973e+07</td>\n",
       "      <td>1.169097e+08</td>\n",
       "      <td>0.447511</td>\n",
       "      <td>3818.449449</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>min</th>\n",
       "      <td>4.536800e+04</td>\n",
       "      <td>6.680000e+02</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>8.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25%</th>\n",
       "      <td>3.074049e+07</td>\n",
       "      <td>1.005758e+08</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>3673.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>50%</th>\n",
       "      <td>7.239110e+07</td>\n",
       "      <td>2.014565e+08</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>6071.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>75%</th>\n",
       "      <td>1.079523e+08</td>\n",
       "      <td>3.030153e+08</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>10314.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>max</th>\n",
       "      <td>1.424302e+08</td>\n",
       "      <td>4.045522e+08</td>\n",
       "      <td>4.000000</td>\n",
       "      <td>14080.000000</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "            user_id       item_id  behavior_type  item_category\n",
       "count  1.000000e+05  1.000000e+05  100000.000000  100000.000000\n",
       "mean   7.038601e+07  2.018416e+08       1.100130    6837.302220\n",
       "std    4.260973e+07  1.169097e+08       0.447511    3818.449449\n",
       "min    4.536800e+04  6.680000e+02       1.000000       8.000000\n",
       "25%    3.074049e+07  1.005758e+08       1.000000    3673.000000\n",
       "50%    7.239110e+07  2.014565e+08       1.000000    6071.000000\n",
       "75%    1.079523e+08  3.030153e+08       1.000000   10314.000000\n",
       "max    1.424302e+08  4.045522e+08       4.000000   14080.000000"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.describe()  #可以直接通过描述性统计方法查看"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ae0107d5-e008-4240-b68d-a6eae45d4b1b",
   "metadata": {},
   "source": [
    "### 检查重复值\n",
    "- 目标：识别数据集中是否存在重复记录\n",
    "- 理由：重复值会导致数据偏差，确保每条记录的唯一性是数据清洗的重要步骤"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "60ba8a28-7f67-4ea9-8575-b101f5e11611",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.92542"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.drop_duplicates().shape[0] / data.shape[0]  #存在一定的重复值"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d192b0ee-363a-4db3-9ec4-43eb23584494",
   "metadata": {},
   "source": [
    "### 处理时间数据\n",
    "- 提取时间信息\n",
    "  - 目标：从time字段中提取出年、月、日、时、分、秒等信息\n",
    "  - 理由：细化时间分析能够帮助识别用户行为的高峰期及周期性，支持数据驱动的决策"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "7158f16a-9e39-4597-9860-fbb82ef0b8f0",
   "metadata": {},
   "outputs": [],
   "source": [
    "#将time转换为日期时间格式\n",
    "data['time'] = pd.to_datetime(data['time'], format='%Y-%m-%d %H')\n",
    "\n",
    "#提取天\n",
    "data['day'] = data['time'].dt.day\n",
    "\n",
    "#提取天名称\n",
    "data['day_name'] = data['time'].dt.day_name()\n",
    "\n",
    "#提取小时\n",
    "data['hour'] = data['time'].dt.hour\n",
    "\n",
    "#提取月份你\n",
    "data['month'] = data['time'].dt.month\n",
    "\n",
    "#提取月份和日期\n",
    "data['md'] = data['time'].apply(lambda x:x.strftime('%m-%d'))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9ade1a5d-5f17-4e7c-b3fe-fc14fdc81bde",
   "metadata": {},
   "source": [
    "- 以上操作将根据指定的日期时间将time转换为日期时间格式，并使用.dt属性和相应的方法提取出天、星期名称、小时和月份，并将其存储在新的列中\n",
    "- 由于时间格式为'%Y-%m-%d %H'即年份-月份-日期 小时，所以在pd.to_datetime中使用format进行格式化指定正确的格式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "bd53c964-a937-4800-a1ac-80f662b9f983",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user_id</th>\n",
       "      <th>item_id</th>\n",
       "      <th>behavior_type</th>\n",
       "      <th>item_category</th>\n",
       "      <th>time</th>\n",
       "      <th>day</th>\n",
       "      <th>day_name</th>\n",
       "      <th>hour</th>\n",
       "      <th>md</th>\n",
       "      <th>month</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>98047837</td>\n",
       "      <td>232431562</td>\n",
       "      <td>1</td>\n",
       "      <td>4245</td>\n",
       "      <td>2014-12-06 02:00:00</td>\n",
       "      <td>6</td>\n",
       "      <td>Saturday</td>\n",
       "      <td>2</td>\n",
       "      <td>12-06</td>\n",
       "      <td>12</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>97726136</td>\n",
       "      <td>383583590</td>\n",
       "      <td>1</td>\n",
       "      <td>5894</td>\n",
       "      <td>2014-12-09 20:00:00</td>\n",
       "      <td>9</td>\n",
       "      <td>Tuesday</td>\n",
       "      <td>20</td>\n",
       "      <td>12-09</td>\n",
       "      <td>12</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>98607707</td>\n",
       "      <td>64749712</td>\n",
       "      <td>1</td>\n",
       "      <td>2883</td>\n",
       "      <td>2014-12-18 11:00:00</td>\n",
       "      <td>18</td>\n",
       "      <td>Thursday</td>\n",
       "      <td>11</td>\n",
       "      <td>12-18</td>\n",
       "      <td>12</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>98662432</td>\n",
       "      <td>320593836</td>\n",
       "      <td>1</td>\n",
       "      <td>6562</td>\n",
       "      <td>2014-12-06 10:00:00</td>\n",
       "      <td>6</td>\n",
       "      <td>Saturday</td>\n",
       "      <td>10</td>\n",
       "      <td>12-06</td>\n",
       "      <td>12</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>98145908</td>\n",
       "      <td>290208520</td>\n",
       "      <td>1</td>\n",
       "      <td>13926</td>\n",
       "      <td>2014-12-16 21:00:00</td>\n",
       "      <td>16</td>\n",
       "      <td>Tuesday</td>\n",
       "      <td>21</td>\n",
       "      <td>12-16</td>\n",
       "      <td>12</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    user_id    item_id  behavior_type  item_category                time  day  \\\n",
       "0  98047837  232431562              1           4245 2014-12-06 02:00:00    6   \n",
       "1  97726136  383583590              1           5894 2014-12-09 20:00:00    9   \n",
       "2  98607707   64749712              1           2883 2014-12-18 11:00:00   18   \n",
       "3  98662432  320593836              1           6562 2014-12-06 10:00:00    6   \n",
       "4  98145908  290208520              1          13926 2014-12-16 21:00:00   16   \n",
       "\n",
       "   day_name  hour     md  month  \n",
       "0  Saturday     2  12-06     12  \n",
       "1   Tuesday    20  12-09     12  \n",
       "2  Thursday    11  12-18     12  \n",
       "3  Saturday    10  12-06     12  \n",
       "4   Tuesday    21  12-16     12  "
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# data.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7528ac33-184b-4184-83b0-016cce5bbc58",
   "metadata": {},
   "source": [
    "如果data.head()读取慢，则可以使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c2e8a08e-5896-4afd-a59c-2dea5d93f541",
   "metadata": {},
   "outputs": [],
   "source": [
    "data.iloc[:5,:]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "59175799-60f6-4748-9860-030a8f5f3a5d",
   "metadata": {},
   "source": [
    "## 计算PV"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "2d5c332a-6d0b-4fa1-b7ae-7047093d9976",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PV:  100000\n",
      "UV:  899\n"
     ]
    }
   ],
   "source": [
    "#计算PV\n",
    "pv = data['user_id'].count()\n",
    "print(\"PV: \", pv)\n",
    "\n",
    "#计算 UV\n",
    "uv = data['user_id'].nunique()\n",
    "print(\"UV: \", uv)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "be450c83-0d0c-4b45-9c6a-6af6ddbb4c5c",
   "metadata": {},
   "source": [
    "时间趋势分析可以帮助了解PV和UV在不同时间维度上的变化情况，都可以按照年月、星期几、小时和天进行PV和UV分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "0b5fe845-82d0-43c0-b8a0-38292d7a73f4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PV by Month: \n",
      " month\n",
      "11    38287\n",
      "12    61713\n",
      "Name: user_id, dtype: int64\n",
      "UV by Month: \n",
      " month\n",
      "11    847\n",
      "12    883\n",
      "Name: user_id, dtype: int64\n"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import pyecharts.options as opts\n",
    "from pyecharts.charts import Bar\n",
    "from pyecharts.charts import Scatter\n",
    "from pyecharts.charts import Line\n",
    "from pyecharts.charts import Pie\n",
    "from pyecharts.charts import Map\n",
    "from pyecharts.charts import Geo\n",
    "from pyecharts.globals import JsCode\n",
    "from pyecharts.globals import ThemeType\n",
    "\n",
    "#按月份统计PV和UV\n",
    "pv_month = data.groupby(data['month'])['user_id'].count()\n",
    "uv_month = data.groupby(data['month'])['user_id'].nunique()\n",
    "\n",
    "#打印月份PV和UV\n",
    "print(\"PV by Month: \\n\", pv_month)\n",
    "print(\"UV by Month: \\n\", uv_month)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "84079e53-9666-45cc-838f-3a71599c3f1d",
   "metadata": {},
   "outputs": [],
   "source": [
    "#自定义样式\n",
    "itemstyle = {\n",
    "    'normal': {\n",
    "        'shadowColor': 'rgba(0,0,0,.5)',\n",
    "        'shadowBlur': 5,\n",
    "        'borderRadius': 10,\n",
    "        'shadowOffsetY': 5,\n",
    "        'shadowOffsetX': 5,\n",
    "        'opacity': 0.7\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "e223d490-2b43-4aa0-aec0-b0c1ac7a582e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'D:\\\\jupyter\\\\淘宝用户购物行为数据分析\\\\render.html'"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pie = (\n",
    "    Pie(init_opts=opts.InitOpts(theme=ThemeType.CHALK))\n",
    "    .add('PV', pv_month.reset_index().values.tolist(),  #添加轴中的数据\n",
    "        radius=[40, 90],\n",
    "        itemstyle_opts=itemstyle,\n",
    "        center=['30%', '50%']    #饼图的位置\n",
    "        )\n",
    "    .add('UV', uv_month.reset_index().values.tolist(),\n",
    "        radius=[40, 90],\n",
    "        center=['70%', '50%'],\n",
    "        itemstyle_opts=itemstyle\n",
    "        )\n",
    "    .set_series_opts(label_opts=opts.LabelOpts(formatter=\"{b}月占比：{d}%\"))\n",
    "    .set_global_opts(\n",
    "        title_opts=[\n",
    "            dict(text='PV占比',top='48%',left='26.5%',\n",
    "                textStyle=opts.TextStyleOpts(font_size=16, color='cyan')),\n",
    "            dict(text='UV占比',top='48%',left='66.5%',\n",
    "                textStyle=opts.TextStyleOpts(font_size=16, color='cyan'))],\n",
    "        legend_opts=opts.LegendOpts(is_show=False)\n",
    "    )\n",
    ")\n",
    "pie.render()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6c4f488e-0ab5-4fe4-9357-4713fa8edeb5",
   "metadata": {},
   "source": [
    "### 按星期几分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "9ba26869-4293-41ba-ae1d-95526e0b2e9a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PV by Day of week: \n",
      " day_name\n",
      "Friday       14591\n",
      "Monday       12910\n",
      "Saturday     12181\n",
      "Sunday       13318\n",
      "Thursday     15778\n",
      "Tuesday      15510\n",
      "Wednesday    15712\n",
      "Name: user_id, dtype: int64\n",
      "UV by Day of week: \n",
      " day_name\n",
      "Friday       799\n",
      "Monday       784\n",
      "Saturday     754\n",
      "Sunday       763\n",
      "Thursday     809\n",
      "Tuesday      808\n",
      "Wednesday    801\n",
      "Name: user_id, dtype: int64\n"
     ]
    }
   ],
   "source": [
    "#按星期几统计PV和UV\n",
    "pv_day_name = data.groupby(data['day_name'])['user_id'].count()\n",
    "uv_day_name = data.groupby(data['day_name'])['user_id'].nunique()\n",
    "print(\"PV by Day of week: \\n\", pv_day_name)\n",
    "print(\"UV by Day of week: \\n\", uv_day_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "fe39b125-514a-4538-bff3-5d13a34818e3",
   "metadata": {},
   "outputs": [],
   "source": [
    "data_pv = pv_day_name.reset_index().values.tolist()\n",
    "data_uv = uv_day_name.reset_index().values.tolist()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "ca5253d3-8845-4f2c-b562-152ab9bbdd35",
   "metadata": {},
   "outputs": [],
   "source": [
    "#自定义样式\n",
    "itemstyle1 = {\n",
    "    'normal': {\n",
    "        'color': \"skyblue\",\n",
    "        'shadowColor': 'rgba(0,0,0,.3)',\n",
    "        'shadowBlur': 0,\n",
    "        'shadowOffsetY': 2,\n",
    "        'shadowOffsetX': 2,\n",
    "        'width': 2\n",
    "    }\n",
    "}\n",
    "itemstyle2 = {\n",
    "    'normal': {\n",
    "        'color': \"pink\",\n",
    "        'shadowColor': 'rgba(0,0,0,.3)',\n",
    "        'shadowBlur': 0,\n",
    "        'shadowOffsetY': 2,\n",
    "        'shadowOffsetX': 2,\n",
    "        'width': 2\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "e5ded5f4-2fe7-4bf0-bb2c-2775578df7b2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'D:\\\\jupyter\\\\淘宝用户购物行为数据分析\\\\按星期分析图.html'"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bar = (\n",
    "    Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))\n",
    "    .add_xaxis([i[0] for i in data_pv])\n",
    "    .add_yaxis(\"PV\", [i[1] for i in data_pv], itemstyle_opts=itemstyle1)\n",
    "    .add_yaxis(\"UV\", [i[1] for i in data_uv], itemstyle_opts=itemstyle2)\n",
    "    .set_series_opts(label_opts=opts.LabelOpts(is_show=True, position='top'))\n",
    "    .set_global_opts(title_opts=opts.TitleOpts('周PV和UV变化折线图', pos_left='center'),\n",
    "                    legend_opts=opts.LegendOpts(selected_map={\"PV\":True,'UV':False}),\n",
    "                    tooltip_opts=opts.TooltipOpts(trigger='axis', axis_pointer_type='shadow'),\n",
    "                    xaxis_opts=opts.AxisOpts(splitline_opts=opts.SplitLineOpts(is_show=False)),\n",
    "                    yaxis_opts=opts.AxisOpts(splitline_opts=opts.SplitLineOpts(is_show=False)))\n",
    ")\n",
    "bar.render('按星期分析图.html')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0a53a4b5-00f6-4c51-a3d3-8d5c39dd98b0",
   "metadata": {},
   "source": [
    "### 按天分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "5f743439-45d9-4535-a031-f860c98e959e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PV by Day: \n",
      " md\n",
      "11-18    3006\n",
      "11-19    2614\n",
      "11-20    2846\n",
      "11-21    2785\n",
      "11-22    2615\n",
      "11-23    3153\n",
      "11-24    3044\n",
      "11-25    2967\n",
      "11-26    2949\n",
      "11-27    2814\n",
      "11-28    2791\n",
      "11-29    3088\n",
      "11-30    3615\n",
      "12-01    3277\n",
      "12-02    3262\n",
      "12-03    3289\n",
      "12-04    3096\n",
      "12-05    2987\n",
      "12-06    3104\n",
      "12-07    3346\n",
      "12-08    3105\n",
      "12-09    3031\n",
      "12-10    3675\n",
      "12-11    3977\n",
      "12-12    6028\n",
      "12-13    3374\n",
      "12-14    3204\n",
      "12-15    3484\n",
      "12-16    3244\n",
      "12-17    3185\n",
      "12-18    3045\n",
      "Name: user_id, dtype: int64\n",
      "UV by Day: \n",
      " md\n",
      "11-18    440\n",
      "11-19    414\n",
      "11-20    442\n",
      "11-21    447\n",
      "11-22    431\n",
      "11-23    452\n",
      "11-24    446\n",
      "11-25    451\n",
      "11-26    430\n",
      "11-27    436\n",
      "11-28    442\n",
      "11-29    459\n",
      "11-30    458\n",
      "12-01    462\n",
      "12-02    464\n",
      "12-03    457\n",
      "12-04    452\n",
      "12-05    448\n",
      "12-06    470\n",
      "12-07    474\n",
      "12-08    482\n",
      "12-09    478\n",
      "12-10    490\n",
      "12-11    519\n",
      "12-12    618\n",
      "12-13    467\n",
      "12-14    461\n",
      "12-15    472\n",
      "12-16    485\n",
      "12-17    475\n",
      "12-18    446\n",
      "Name: user_id, dtype: int64\n"
     ]
    }
   ],
   "source": [
    "#按天统计PV和UV\n",
    "pv_day = data.groupby(data['md'])['user_id'].count()\n",
    "uv_day = data.groupby(data['md'])['user_id'].nunique()\n",
    "print(\"PV by Day: \\n\", pv_day)\n",
    "print(\"UV by Day: \\n\", uv_day)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "0128fbff-96e2-4cc5-b9db-4295b093430e",
   "metadata": {},
   "outputs": [],
   "source": [
    "data_pv = pv_day.reset_index().values.tolist()\n",
    "data_uv = uv_day.reset_index().values.tolist()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "2516c2bc-66e6-4e68-995b-86a432a8ad85",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'D:\\\\jupyter\\\\淘宝用户购物行为数据分析\\\\按天统计分析.html'"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#可以自行编写折线图，这里先写柱形图\n",
    "bar = (\n",
    "    Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))\n",
    "    .add_xaxis([f\"{i[0]}\" for i in data_pv])\n",
    "    .add_yaxis(\"PV\", [i[1] for i in data_pv],\n",
    "              itemstyle_opts=itemstyle1)\n",
    "    .add_yaxis(\"UV\", [i[1] for i in data_uv], itemstyle_opts=itemstyle2)\n",
    "    .set_series_opts(label_opts=opts.LabelOpts(is_show=False))\n",
    "    .set_global_opts(title_opts=opts.TitleOpts('周PV和UV变化柱形图', pos_left='center'),\n",
    "                    legend_opts=opts.LegendOpts(selected_map={'PV':False,'UV':True}),\n",
    "                    tooltip_opts=opts.TooltipOpts(trigger='axis',axis_pointer_type='shadow'),\n",
    "                    datazoom_opts=opts.DataZoomOpts(),\n",
    "                    xaxis_opts=opts.AxisOpts(splitline_opts=opts.SplitLineOpts(is_show=False)),\n",
    "                    yaxis_opts=opts.AxisOpts(splitline_opts=opts.SplitLineOpts(is_show=False)),\n",
    "                    )\n",
    ")\n",
    "bar.render('按天统计分析.html')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "943cb121-6238-455b-9194-f78cca3c75ba",
   "metadata": {},
   "source": [
    "### 按小时分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "c5dedd20-66c4-42c4-b2b8-c393faca5240",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PV by Hour: \n",
      " hour\n",
      "0     4115\n",
      "1     2185\n",
      "2     1252\n",
      "3      638\n",
      "4      381\n",
      "5      692\n",
      "6     1272\n",
      "7     2278\n",
      "8     2981\n",
      "9     3842\n",
      "10    4459\n",
      "11    4479\n",
      "12    4508\n",
      "13    5005\n",
      "14    4911\n",
      "15    4768\n",
      "16    4942\n",
      "17    4310\n",
      "18    4586\n",
      "19    6119\n",
      "20    7997\n",
      "21    8861\n",
      "22    8740\n",
      "23    6679\n",
      "Name: user_id, dtype: int64\n",
      "UV by Hour: \n",
      " hour\n",
      "0     402\n",
      "1     254\n",
      "2     173\n",
      "3     108\n",
      "4      96\n",
      "5     119\n",
      "6     214\n",
      "7     367\n",
      "8     460\n",
      "9     553\n",
      "10    585\n",
      "11    590\n",
      "12    607\n",
      "13    622\n",
      "14    602\n",
      "15    604\n",
      "16    614\n",
      "17    613\n",
      "18    609\n",
      "19    651\n",
      "20    697\n",
      "21    720\n",
      "22    691\n",
      "23    569\n",
      "Name: user_id, dtype: int64\n"
     ]
    }
   ],
   "source": [
    "#按小时统计pv和uv\n",
    "pv_hour = data.groupby(data['hour'])['user_id'].count()\n",
    "uv_hour = data.groupby(data['hour'])['user_id'].nunique()\n",
    "print(\"PV by Hour: \\n\", pv_hour)\n",
    "print(\"UV by Hour: \\n\", uv_hour)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "faab3d93-6e34-4691-8c22-1e8d2b0642c3",
   "metadata": {},
   "outputs": [],
   "source": [
    "data_pv = pv_hour.reset_index().values.tolist()\n",
    "data_uv = uv_hour.reset_index().values.tolist()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "9deca3fa-8740-4f3e-989c-0055295d8aae",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'D:\\\\jupyter\\\\淘宝用户购物行为数据分析\\\\按小时分析折线图.html'"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#可以做两个轴\n",
    "line = (\n",
    "    Line(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))\n",
    "    .add_xaxis([i[0] for i in data_pv])\n",
    "    .add_yaxis(\"PV\", [i[1] for i in data_pv],linestyle_opts=itemstyle1, is_smooth=True,\n",
    "              is_symbol_show=False)\n",
    "    .add_yaxis(\"UV\", [i[1] for i in data_uv], linestyle_opts=itemstyle2, is_smooth=True,\n",
    "              is_symbol_show=False)\n",
    "    .set_series_opts(label_opts=opts.LabelOpts(is_show=False))\n",
    "    .set_global_opts(title_opts=opts.TitleOpts('周PV和UV变化折线图', pos_left='center'),\n",
    "                    tooltip_opts=opts.TooltipOpts(trigger='axis',axis_pointer_type='cross'),\n",
    "                    xaxis_opts=opts.AxisOpts(splitline_opts=opts.SplitLineOpts(is_show=False)),\n",
    "                    yaxis_opts=opts.AxisOpts(splitline_opts=opts.SplitLineOpts(is_show=False)),\n",
    "                    )\n",
    ")\n",
    "line.render('按小时分析折线图.html')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5415dd35-cc1d-42d7-8542-a9e28024f4e5",
   "metadata": {},
   "source": [
    "### 节假日操作"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "7faabd48-fa6c-4dd6-9fac-e4e7009f5cd3",
   "metadata": {},
   "outputs": [],
   "source": [
    "hours = [\n",
    "    '0a/12p', '1a', '2a', '3a', '4a', '5a', '6a', '7a', '8a', '9a', '10a', '11a',\n",
    "    '12a/0p', '1p', '2p', '3p', '4p', '5p', '6p', '7p', '8p', '9p', '10p', '11p'\n",
    "]\n",
    "\n",
    "weekday_mapping = {\n",
    "    'Monday': '周一',\n",
    "    'Tuesday': '周二',\n",
    "    'Wednesday': '周三',\n",
    "    'Thursday': '周四',\n",
    "    'Friday': '周五',\n",
    "    'Saturday': '周六',\n",
    "    'Sunday': '周日'\n",
    "}\n",
    "weeks = ['周一','周二','周三','周四','周五','周六','周日']\n",
    "data_uv = data.groupby(['day_name', 'hour'])['user_id'].count().reset_index()\n",
    "data_uv['day_name'] = data_uv['day_name'].map(weekday_mapping)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "id": "418d9530-ef8f-4ebe-a33c-6749b0f32abd",
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.preprocessing import MinMaxScaler\n",
    "\n",
    "# data是原始数据，形状为(n_samples, n_features) 样本集，特征集\n",
    "# 如果data是一维数组将其转换为二维数组，使用data.reshape(-1, 1)来实现\n",
    "\n",
    "# 首先创建MinMaxScaler对象，并指定目标范围为 1到100\n",
    "scaler = MinMaxScaler(feature_range=(1,50))\n",
    "\n",
    "# 使用fit_transform进行数据缩放\n",
    "scaled_data = scaler.fit_transform(data_uv[['user_id']])\n",
    "\n",
    "#如果需要再次将数据缩放回原始范围，可以使用inverse_transform方法\n",
    "# inverse_data = scaler.inverse_transform(scaled_data)\n",
    "data_uv['size'] = scaled_data.astype('int')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "id": "6bf2f26c-0b89-41ba-8393-adab905c40bd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[['周五', 0, 728, 25],\n",
       " ['周五', 1, 434, 15],\n",
       " ['周五', 2, 187, 6],\n",
       " ['周五', 3, 77, 2],\n",
       " ['周五', 4, 66, 2],\n",
       " ['周五', 5, 123, 4],\n",
       " ['周五', 6, 225, 7],\n",
       " ['周五', 7, 401, 13],\n",
       " ['周五', 8, 449, 15],\n",
       " ['周五', 9, 557, 19],\n",
       " ['周五', 10, 691, 23],\n",
       " ['周五', 11, 670, 23],\n",
       " ['周五', 12, 695, 24],\n",
       " ['周五', 13, 636, 22],\n",
       " ['周五', 14, 789, 27],\n",
       " ['周五', 15, 683, 23],\n",
       " ['周五', 16, 712, 24],\n",
       " ['周五', 17, 607, 21],\n",
       " ['周五', 18, 619, 21],\n",
       " ['周五', 19, 784, 27],\n",
       " ['周五', 20, 1046, 36],\n",
       " ['周五', 21, 1314, 45],\n",
       " ['周五', 22, 1157, 40],\n",
       " ['周五', 23, 941, 32],\n",
       " ['周一', 0, 498, 17],\n",
       " ['周一', 1, 281, 9],\n",
       " ['周一', 2, 155, 5],\n",
       " ['周一', 3, 99, 3],\n",
       " ['周一', 4, 39, 1],\n",
       " ['周一', 5, 96, 3],\n",
       " ['周一', 6, 180, 6],\n",
       " ['周一', 7, 247, 8],\n",
       " ['周一', 8, 327, 11],\n",
       " ['周一', 9, 470, 16],\n",
       " ['周一', 10, 518, 17],\n",
       " ['周一', 11, 630, 21],\n",
       " ['周一', 12, 633, 21],\n",
       " ['周一', 13, 700, 24],\n",
       " ['周一', 14, 657, 22],\n",
       " ['周一', 15, 570, 19],\n",
       " ['周一', 16, 592, 20],\n",
       " ['周一', 17, 538, 18],\n",
       " ['周一', 18, 598, 20],\n",
       " ['周一', 19, 928, 32],\n",
       " ['周一', 20, 1038, 35],\n",
       " ['周一', 21, 1146, 39],\n",
       " ['周一', 22, 1233, 42],\n",
       " ['周一', 23, 737, 25],\n",
       " ['周六', 0, 523, 18],\n",
       " ['周六', 1, 256, 8],\n",
       " ['周六', 2, 159, 5],\n",
       " ['周六', 3, 117, 4],\n",
       " ['周六', 4, 65, 2],\n",
       " ['周六', 5, 66, 2],\n",
       " ['周六', 6, 160, 5],\n",
       " ['周六', 7, 366, 12],\n",
       " ['周六', 8, 425, 14],\n",
       " ['周六', 9, 459, 15],\n",
       " ['周六', 10, 562, 19],\n",
       " ['周六', 11, 563, 19],\n",
       " ['周六', 12, 476, 16],\n",
       " ['周六', 13, 601, 20],\n",
       " ['周六', 14, 616, 21],\n",
       " ['周六', 15, 539, 18],\n",
       " ['周六', 16, 603, 20],\n",
       " ['周六', 17, 543, 18],\n",
       " ['周六', 18, 563, 19],\n",
       " ['周六', 19, 728, 25],\n",
       " ['周六', 20, 913, 31],\n",
       " ['周六', 21, 982, 33],\n",
       " ['周六', 22, 1043, 36],\n",
       " ['周六', 23, 853, 29],\n",
       " ['周日', 0, 576, 19],\n",
       " ['周日', 1, 276, 9],\n",
       " ['周日', 2, 181, 6],\n",
       " ['周日', 3, 76, 2],\n",
       " ['周日', 4, 33, 1],\n",
       " ['周日', 5, 29, 1],\n",
       " ['周日', 6, 135, 4],\n",
       " ['周日', 7, 283, 9],\n",
       " ['周日', 8, 444, 15],\n",
       " ['周日', 9, 507, 17],\n",
       " ['周日', 10, 603, 20],\n",
       " ['周日', 11, 565, 19],\n",
       " ['周日', 12, 596, 20],\n",
       " ['周日', 13, 646, 22],\n",
       " ['周日', 14, 570, 19],\n",
       " ['周日', 15, 640, 22],\n",
       " ['周日', 16, 719, 24],\n",
       " ['周日', 17, 477, 16],\n",
       " ['周日', 18, 653, 22],\n",
       " ['周日', 19, 772, 26],\n",
       " ['周日', 20, 1051, 36],\n",
       " ['周日', 21, 1199, 41],\n",
       " ['周日', 22, 1311, 45],\n",
       " ['周日', 23, 976, 33],\n",
       " ['周四', 0, 546, 18],\n",
       " ['周四', 1, 212, 7],\n",
       " ['周四', 2, 138, 4],\n",
       " ['周四', 3, 109, 3],\n",
       " ['周四', 4, 57, 1],\n",
       " ['周四', 5, 139, 4],\n",
       " ['周四', 6, 192, 6],\n",
       " ['周四', 7, 322, 11],\n",
       " ['周四', 8, 413, 14],\n",
       " ['周四', 9, 635, 21],\n",
       " ['周四', 10, 665, 23],\n",
       " ['周四', 11, 672, 23],\n",
       " ['周四', 12, 774, 26],\n",
       " ['周四', 13, 796, 27],\n",
       " ['周四', 14, 777, 26],\n",
       " ['周四', 15, 788, 27],\n",
       " ['周四', 16, 711, 24],\n",
       " ['周四', 17, 660, 22],\n",
       " ['周四', 18, 767, 26],\n",
       " ['周四', 19, 976, 33],\n",
       " ['周四', 20, 1383, 47],\n",
       " ['周四', 21, 1445, 50],\n",
       " ['周四', 22, 1379, 47],\n",
       " ['周四', 23, 1222, 42],\n",
       " ['周二', 0, 568, 19],\n",
       " ['周二', 1, 343, 11],\n",
       " ['周二', 2, 221, 7],\n",
       " ['周二', 3, 93, 3],\n",
       " ['周二', 4, 71, 2],\n",
       " ['周二', 5, 106, 3],\n",
       " ['周二', 6, 196, 6],\n",
       " ['周二', 7, 333, 11],\n",
       " ['周二', 8, 436, 15],\n",
       " ['周二', 9, 613, 21],\n",
       " ['周二', 10, 724, 25],\n",
       " ['周二', 11, 676, 23],\n",
       " ['周二', 12, 729, 25],\n",
       " ['周二', 13, 855, 29],\n",
       " ['周二', 14, 729, 25],\n",
       " ['周二', 15, 757, 26],\n",
       " ['周二', 16, 782, 27],\n",
       " ['周二', 17, 762, 26],\n",
       " ['周二', 18, 646, 22],\n",
       " ['周二', 19, 995, 34],\n",
       " ['周二', 20, 1256, 43],\n",
       " ['周二', 21, 1375, 47],\n",
       " ['周二', 22, 1225, 42],\n",
       " ['周二', 23, 1019, 35],\n",
       " ['周三', 0, 676, 23],\n",
       " ['周三', 1, 383, 13],\n",
       " ['周三', 2, 211, 7],\n",
       " ['周三', 3, 67, 2],\n",
       " ['周三', 4, 50, 1],\n",
       " ['周三', 5, 133, 4],\n",
       " ['周三', 6, 184, 6],\n",
       " ['周三', 7, 326, 11],\n",
       " ['周三', 8, 487, 16],\n",
       " ['周三', 9, 601, 20],\n",
       " ['周三', 10, 696, 24],\n",
       " ['周三', 11, 703, 24],\n",
       " ['周三', 12, 605, 20],\n",
       " ['周三', 13, 771, 26],\n",
       " ['周三', 14, 773, 26],\n",
       " ['周三', 15, 791, 27],\n",
       " ['周三', 16, 823, 28],\n",
       " ['周三', 17, 723, 25],\n",
       " ['周三', 18, 740, 25],\n",
       " ['周三', 19, 936, 32],\n",
       " ['周三', 20, 1310, 45],\n",
       " ['周三', 21, 1400, 48],\n",
       " ['周三', 22, 1392, 48],\n",
       " ['周三', 23, 931, 32]]"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "allinfo = data_uv.values.tolist()\n",
    "allinfo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "e77c8bfa-b74e-42e1-b223-915552382571",
   "metadata": {},
   "outputs": [],
   "source": [
    "labeljs2 = \"\"\"function(p) {console.log(p); return '时间：' + String(p.data[0]) + '\\\\t\\\\n' + 'UV数量：' + String(p.data[1]);}\"\"\"\n",
    "single_axis, titles = [], []\n",
    "scatter = Scatter(init_opts=opts.InitOpts(width='1000px', height='700px', theme='light', bg_color='#0d0735'))\n",
    "for idx, day in enumerate(weeks[::-1]):\n",
    "    scatter.add_xaxis(xaxis_data=hours)\n",
    "    #单轴配置\n",
    "    single_axis.append({'left': 100,\n",
    "                        'nameGap': 20,\n",
    "                        'nameLocation': 'start',\n",
    "                        'type': 'category',\n",
    "                        'boundaryGap': False,\n",
    "                        'data': hours,\n",
    "                        'top': '{}%'.format(idx * 100 / 7 + 5),\n",
    "                        'height': '{}%'.format(100 / 7 - 10),\n",
    "                        'gridIndex': idx,\n",
    "                        'axisLabel': {'interval': 2, 'color': '#9FC131'}\n",
    "    })\n",
    "    titles.append(dict(text=day,top='{}%'.format(idx * 100 / 7 + 6), left='2%',\n",
    "                     textStyle=dict(color='#fff200')))\n",
    "    scatter.add_yaxis('',\n",
    "                     y_axis=[(int(item[2]),int(item[3])) for item in allinfo if item[0] == day],\n",
    "                     symbol_size=JsCode('function(p){console.log(p); return p[2];}'),\n",
    "                     label_opts=opts.LabelOpts(is_show=False)\n",
    "                     )\n",
    "    scatter.options['series'][idx]['coordinateSystem'] = 'singleAxis'\n",
    "    scatter.options['series'][idx]['singleAxisIndex'] = idx\n",
    "    scatter.options['singleAxis'] = single_axis\n",
    "    scatter.set_global_opts(\n",
    "        tooltip_opts=opts.TooltipOpts(formatter=JsCode(labeljs2)),\n",
    "        xaxis_opts=opts.AxisOpts(is_show=False),\n",
    "        yaxis_opts=opts.AxisOpts(is_show=False),\n",
    "        title_opts=titles,  #多个标题\n",
    "    )\n",
    "    scatter.render('节假日散点图.html')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9748dfd2-3c4c-49ce-9ed4-7d8908384563",
   "metadata": {},
   "source": [
    "不同日期的小时-流量"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0551434c-7eb3-4086-9ee6-c40fcd9cd0ea",
   "metadata": {},
   "source": [
    "周末（11月22、23、29、30日；12月6、7日）和工作日人们的生活作息可能不太一致，以及双十一活动当天和12月11日（临界）\n",
    "可能用户会更加关注，对应时间段的流量可能也会不同。所以进行单独分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "778f3b8c-4e49-49d0-9371-836a32b5c4a1",
   "metadata": {},
   "outputs": [],
   "source": [
    "hours = [\n",
    "    '0a/12p', '1a', '2a', '3a', '4a', '5a', '6a', '7a', '8a', '9a', '10a', '11a',\n",
    "    '12a/0p', '1p', '2p', '3p', '4p', '5p', '6p', '7p', '8p', '9p', '10p', '11p'\n",
    "]\n",
    "\n",
    "days = ['11-22', '11-23', '11-29', '12-06', '12-07', '12-11', '12-12']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "id": "950adad5-e9c5-44d7-b541-990e97ab06d3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[['11-22', 0, 101, 9],\n",
       " ['11-22', 1, 59, 6],\n",
       " ['11-22', 2, 24, 3],\n",
       " ['11-22', 3, 16, 2],\n",
       " ['11-22', 4, 23, 2],\n",
       " ['11-22', 5, 21, 2],\n",
       " ['11-22', 6, 29, 3],\n",
       " ['11-22', 7, 67, 6],\n",
       " ['11-22', 8, 84, 8],\n",
       " ['11-22', 9, 107, 10],\n",
       " ['11-22', 10, 114, 11],\n",
       " ['11-22', 11, 141, 13],\n",
       " ['11-22', 12, 105, 10],\n",
       " ['11-22', 13, 132, 12],\n",
       " ['11-22', 14, 94, 9],\n",
       " ['11-22', 15, 139, 13],\n",
       " ['11-22', 16, 148, 14],\n",
       " ['11-22', 17, 105, 10],\n",
       " ['11-22', 18, 138, 13],\n",
       " ['11-22', 19, 183, 17],\n",
       " ['11-22', 20, 206, 19],\n",
       " ['11-22', 21, 202, 18],\n",
       " ['11-22', 22, 228, 21],\n",
       " ['11-22', 23, 149, 14],\n",
       " ['11-23', 0, 165, 15],\n",
       " ['11-23', 1, 81, 8],\n",
       " ['11-23', 2, 40, 4],\n",
       " ['11-23', 3, 16, 2],\n",
       " ['11-23', 4, 1, 1],\n",
       " ['11-23', 5, 7, 1],\n",
       " ['11-23', 6, 46, 5],\n",
       " ['11-23', 7, 97, 9],\n",
       " ['11-23', 8, 119, 11],\n",
       " ['11-23', 9, 115, 11],\n",
       " ['11-23', 10, 127, 12],\n",
       " ['11-23', 11, 154, 14],\n",
       " ['11-23', 12, 150, 14],\n",
       " ['11-23', 13, 151, 14],\n",
       " ['11-23', 14, 102, 10],\n",
       " ['11-23', 15, 147, 14],\n",
       " ['11-23', 16, 229, 21],\n",
       " ['11-23', 17, 97, 9],\n",
       " ['11-23', 18, 136, 13],\n",
       " ['11-23', 19, 193, 18],\n",
       " ['11-23', 20, 265, 24],\n",
       " ['11-23', 21, 239, 22],\n",
       " ['11-23', 22, 295, 27],\n",
       " ['11-23', 23, 181, 17],\n",
       " ['11-29', 0, 89, 8],\n",
       " ['11-29', 1, 65, 6],\n",
       " ['11-29', 2, 33, 3],\n",
       " ['11-29', 3, 24, 3],\n",
       " ['11-29', 4, 24, 3],\n",
       " ['11-29', 5, 7, 1],\n",
       " ['11-29', 6, 30, 3],\n",
       " ['11-29', 7, 93, 9],\n",
       " ['11-29', 8, 135, 12],\n",
       " ['11-29', 9, 102, 10],\n",
       " ['11-29', 10, 143, 13],\n",
       " ['11-29', 11, 132, 12],\n",
       " ['11-29', 12, 97, 9],\n",
       " ['11-29', 13, 124, 11],\n",
       " ['11-29', 14, 153, 14],\n",
       " ['11-29', 15, 173, 16],\n",
       " ['11-29', 16, 151, 14],\n",
       " ['11-29', 17, 161, 15],\n",
       " ['11-29', 18, 123, 11],\n",
       " ['11-29', 19, 151, 14],\n",
       " ['11-29', 20, 240, 22],\n",
       " ['11-29', 21, 260, 24],\n",
       " ['11-29', 22, 277, 25],\n",
       " ['11-29', 23, 301, 27],\n",
       " ['12-06', 0, 160, 15],\n",
       " ['12-06', 1, 60, 6],\n",
       " ['12-06', 2, 63, 6],\n",
       " ['12-06', 3, 26, 3],\n",
       " ['12-06', 4, 6, 1],\n",
       " ['12-06', 5, 12, 1],\n",
       " ['12-06', 6, 25, 3],\n",
       " ['12-06', 7, 131, 12],\n",
       " ['12-06', 8, 87, 8],\n",
       " ['12-06', 9, 101, 9],\n",
       " ['12-06', 10, 155, 14],\n",
       " ['12-06', 11, 155, 14],\n",
       " ['12-06', 12, 114, 11],\n",
       " ['12-06', 13, 194, 18],\n",
       " ['12-06', 14, 156, 14],\n",
       " ['12-06', 15, 154, 14],\n",
       " ['12-06', 16, 167, 15],\n",
       " ['12-06', 17, 124, 11],\n",
       " ['12-06', 18, 125, 12],\n",
       " ['12-06', 19, 181, 17],\n",
       " ['12-06', 20, 195, 18],\n",
       " ['12-06', 21, 271, 25],\n",
       " ['12-06', 22, 251, 23],\n",
       " ['12-06', 23, 191, 17],\n",
       " ['12-07', 0, 161, 15],\n",
       " ['12-07', 1, 59, 6],\n",
       " ['12-07', 2, 29, 3],\n",
       " ['12-07', 3, 13, 2],\n",
       " ['12-07', 4, 5, 1],\n",
       " ['12-07', 5, 9, 1],\n",
       " ['12-07', 6, 40, 4],\n",
       " ['12-07', 7, 54, 5],\n",
       " ['12-07', 8, 134, 12],\n",
       " ['12-07', 9, 154, 14],\n",
       " ['12-07', 10, 144, 13],\n",
       " ['12-07', 11, 144, 13],\n",
       " ['12-07', 12, 188, 17],\n",
       " ['12-07', 13, 187, 17],\n",
       " ['12-07', 14, 172, 16],\n",
       " ['12-07', 15, 139, 13],\n",
       " ['12-07', 16, 151, 14],\n",
       " ['12-07', 17, 106, 10],\n",
       " ['12-07', 18, 162, 15],\n",
       " ['12-07', 19, 197, 18],\n",
       " ['12-07', 20, 220, 20],\n",
       " ['12-07', 21, 287, 26],\n",
       " ['12-07', 22, 304, 28],\n",
       " ['12-07', 23, 287, 26],\n",
       " ['12-11', 0, 110, 10],\n",
       " ['12-11', 1, 46, 5],\n",
       " ['12-11', 2, 41, 4],\n",
       " ['12-11', 3, 24, 3],\n",
       " ['12-11', 4, 7, 1],\n",
       " ['12-11', 5, 14, 2],\n",
       " ['12-11', 6, 37, 4],\n",
       " ['12-11', 7, 55, 5],\n",
       " ['12-11', 8, 89, 8],\n",
       " ['12-11', 9, 185, 17],\n",
       " ['12-11', 10, 170, 16],\n",
       " ['12-11', 11, 159, 15],\n",
       " ['12-11', 12, 211, 19],\n",
       " ['12-11', 13, 188, 17],\n",
       " ['12-11', 14, 177, 16],\n",
       " ['12-11', 15, 150, 14],\n",
       " ['12-11', 16, 173, 16],\n",
       " ['12-11', 17, 177, 16],\n",
       " ['12-11', 18, 184, 17],\n",
       " ['12-11', 19, 287, 26],\n",
       " ['12-11', 20, 379, 34],\n",
       " ['12-11', 21, 336, 30],\n",
       " ['12-11', 22, 372, 34],\n",
       " ['12-11', 23, 406, 37],\n",
       " ['12-12', 0, 371, 34],\n",
       " ['12-12', 1, 301, 27],\n",
       " ['12-12', 2, 121, 11],\n",
       " ['12-12', 3, 30, 3],\n",
       " ['12-12', 4, 52, 5],\n",
       " ['12-12', 5, 66, 6],\n",
       " ['12-12', 6, 124, 11],\n",
       " ['12-12', 7, 180, 16],\n",
       " ['12-12', 8, 224, 20],\n",
       " ['12-12', 9, 248, 23],\n",
       " ['12-12', 10, 323, 29],\n",
       " ['12-12', 11, 234, 21],\n",
       " ['12-12', 12, 220, 20],\n",
       " ['12-12', 13, 237, 22],\n",
       " ['12-12', 14, 287, 26],\n",
       " ['12-12', 15, 274, 25],\n",
       " ['12-12', 16, 309, 28],\n",
       " ['12-12', 17, 226, 21],\n",
       " ['12-12', 18, 227, 21],\n",
       " ['12-12', 19, 291, 26],\n",
       " ['12-12', 20, 365, 33],\n",
       " ['12-12', 21, 550, 50],\n",
       " ['12-12', 22, 417, 38],\n",
       " ['12-12', 23, 351, 32]]"
      ]
     },
     "execution_count": 67,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data1 = data[data['md'].isin(days)]\n",
    "data_uv = data1.groupby(['md', 'hour'])['user_id'].count().reset_index()\n",
    "\n",
    "from sklearn.preprocessing import MinMaxScaler\n",
    "\n",
    "# data是原始数据，形状为(n_samples, n_features) 样本集，特征集\n",
    "# 如果data是一维数组将其转换为二维数组，使用data.reshape(-1, 1)来实现\n",
    "\n",
    "# 创建MinMaxScaler对象，并指定目标范围为 1到100\n",
    "scaler = MinMaxScaler(feature_range=(1,50))\n",
    "\n",
    "# 使用fit_transform进行数据缩放\n",
    "scaled_data = scaler.fit_transform(data_uv[['user_id']])\n",
    "\n",
    "#如果需要再次将数据缩放回原始范围，可以使用inverse_transform方法\n",
    "# inverse_data = scaler.inverse_transform(scaled_data)\n",
    "data_uv['size'] = scaled_data.astype('int')\n",
    "\n",
    "allinfo = data_uv.values.tolist()\n",
    "allinfo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "111d8aed-2586-416d-bd0c-2a3e06edf29c",
   "metadata": {},
   "outputs": [],
   "source": [
    "labeljs2 = \"\"\"function(p) {console.log(p); return '时间：' + String(p.data[0]) + '\\\\t\\\\n' + 'UV数量：' + String(p.data[1]);}\"\"\"\n",
    "single_axis, titles = [], []\n",
    "scatter = Scatter(init_opts=opts.InitOpts(width='1000px', height='700px', theme='light', bg_color='#0d0735'))\n",
    "for idx, day in enumerate(days):\n",
    "    scatter.add_xaxis(xaxis_data=hours)\n",
    "    #单轴配置\n",
    "    single_axis.append({'left': 100,\n",
    "                        'nameGap': 20,\n",
    "                        'nameLocation': 'start',\n",
    "                        'type': 'category',\n",
    "                        'boundaryGap': False,\n",
    "                        'data': hours,\n",
    "                        'top': '{}%'.format(idx * 100 / 7 + 5),\n",
    "                        'height': '{}%'.format(100 / 7 - 10),\n",
    "                        'gridIndex': idx,\n",
    "                        'axisLabel': {'interval': 2, 'color': '#9FC131'}\n",
    "    })\n",
    "    titles.append(dict(text=day,top='{}%'.format(idx * 100 / 7 + 6), left='2%',\n",
    "                     textStyle=dict(color='#fff200')))\n",
    "    scatter.add_yaxis('',\n",
    "                     y_axis=[(int(item[2]),int(item[3])) for item in allinfo if item[0] == day],\n",
    "                     symbol_size=JsCode('function(p){console.log(p); return p[2];}'),\n",
    "                     label_opts=opts.LabelOpts(is_show=False)\n",
    "                     )\n",
    "    scatter.options['series'][idx]['coordinateSystem'] = 'singleAxis'\n",
    "    scatter.options['series'][idx]['singleAxisIndex'] = idx\n",
    "    scatter.options['singleAxis'] = single_axis\n",
    "    scatter.set_global_opts(\n",
    "        tooltip_opts=opts.TooltipOpts(formatter=JsCode(labeljs2)),\n",
    "        xaxis_opts=opts.AxisOpts(is_show=False),\n",
    "        yaxis_opts=opts.AxisOpts(is_show=False),\n",
    "        title_opts=titles,  #多个标题\n",
    "    )\n",
    "    scatter.render('不同日期的小时流量.html')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "id": "21fba629-de60-4653-a510-1fe6a52e78c1",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 也可以采用折线图来完成\n",
    "itemstyle = {\n",
    "    'normal': {\n",
    "        'shadowColor': 'rgba(0,0,0,.5)',\n",
    "        'shadowBlur': 5,  #阴影大小\n",
    "        'borderRadius': 10,\n",
    "        'shadowOffsetY': 5,\n",
    "        'shadowOffsetX': 5,\n",
    "        'opacity': '0.7'\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "id": "e52bea61-97f5-4bf8-8386-5fbd2d4975bf",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'D:\\\\jupyter\\\\淘宝用户购物行为数据分析\\\\折线图描述不同时期小时流量.html'"
      ]
     },
     "execution_count": 71,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "line = Line()\n",
    "colors = ['#0074D9', '#2Ecc40', '#FF4136', '#FF851B',\n",
    "         '#B10DC9', '#111111', '#FF6347']\n",
    "\n",
    "for index,day in enumerate(days):\n",
    "    itemstyle1 = itemstyle.copy()\n",
    "    itemstyle['color'] = colors[index]\n",
    "    line.add_xaxis(xaxis_data=hours)\n",
    "    line.add_yaxis(day,y_axis=[i[2] for i in allinfo if i[0] == day],\n",
    "                  label_opts=opts.LabelOpts(is_show=False),\n",
    "                   is_symbol_show=False,\n",
    "                  linestyle_opts=itemstyle1,\n",
    "                  is_smooth=True,\n",
    "                  )\n",
    "line.set_global_opts(tooltip_opts=opts.TooltipOpts(trigger='axis',axis_pointer_type='cross'),\n",
    "                    legend_opts=opts.LegendOpts(selector=True)\n",
    "                    )\n",
    "line.render('折线图描述不同时期小时流量.html')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "27295106-dd55-4e52-84af-0d45d863a2c7",
   "metadata": {},
   "source": [
    "### 针对“双十二”当天的用户行为分析"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8cdfd8ad-a555-4e30-a05a-699cc72a845c",
   "metadata": {},
   "source": [
    "- 双十二前后的用户行为分析\n",
    "- 接着来分别观察“浏览、收藏、加购物车、购买”这4种行为，分别用数字1、2、3、4表示"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "id": "a01f3ebc-909c-4ac3-a456-a1782160f9a5",
   "metadata": {},
   "outputs": [],
   "source": [
    "r_dict = {1:'点击',2:'收藏',3:'加购物车',4:'支付'}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "id": "ea471c1e-048f-4abf-a811-0808a6d13276",
   "metadata": {},
   "outputs": [],
   "source": [
    "data['mdh'] = data['time'].apply(lambda x:x.strftime('%m-%d %H:%M'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "id": "bd7450b1-cdd9-4de9-a56c-1d27d0e1282d",
   "metadata": {},
   "outputs": [],
   "source": [
    "bth = data[(data['md'] == '12-11') | (data['md'] == '12-12')].groupby(['behavior_type', 'mdh']).count().reset_index()\n",
    "bth['behavior_type'] = bth['behavior_type'].map(r_dict)\n",
    "times = pd.date_range(start='2004-12-11 00:00',\n",
    "                     end='2004-12-12 23:00',\n",
    "                     freq='h').strftime('%m-%d %H:%M').tolist()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "id": "6d616a09-166c-4ba1-8237-6bae40e7c05c",
   "metadata": {},
   "outputs": [],
   "source": [
    "data_pair = {}\n",
    "for i in r_dict.values():\n",
    "    data_pair[i] = bth[bth['behavior_type'] == i].iloc[:,1:].values.tolist()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "id": "17cfcebb-066d-4694-95d1-daf61e29e31c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'D:\\\\jupyter\\\\淘宝用户购物行为数据分析\\\\双十二当天用户行为分析折线图.html'"
      ]
     },
     "execution_count": 84,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "line = Line()\n",
    "colors = ['#0074D9', '#2Ecc40', '#FF4136', '#FF851B',\n",
    "         '#B10DC9', '#111111', '#FF6347']\n",
    "\n",
    "for idx,item in enumerate(r_dict.values()):\n",
    "    itemstyle1 = itemstyle.copy()\n",
    "    itemstyle1['color'] = colors[index]\n",
    "    line.add_xaxis(xaxis_data=times)\n",
    "    line.add_yaxis(item,y_axis=[int(i[1]) for i in data_pair[item]],\n",
    "                  label_opts=opts.LabelOpts(is_show=False),\n",
    "                  is_symbol_show=False,\n",
    "                   linestyle_opts=itemstyle1,\n",
    "                   is_smooth=True\n",
    "                  )\n",
    "line.set_global_opts(tooltip_opts=opts.TooltipOpts(trigger='axis',axis_pointer_type='cross'),\n",
    "                    datazoom_opts=opts.DataZoomOpts(),\n",
    "                    )\n",
    "line.render('双十二当天用户行为分析折线图.html')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4b37d548-a9b0-4027-991c-2c60d6056e78",
   "metadata": {},
   "source": [
    "## 付费用户行为记录"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "5d7a97c0-3259-48c2-a551-808b1d10636a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user_id</th>\n",
       "      <th>item_id</th>\n",
       "      <th>behavior_type</th>\n",
       "      <th>item_category</th>\n",
       "      <th>time</th>\n",
       "      <th>day</th>\n",
       "      <th>day_name</th>\n",
       "      <th>hour</th>\n",
       "      <th>month</th>\n",
       "      <th>md</th>\n",
       "      <th>mdh</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>98047837</td>\n",
       "      <td>232431562</td>\n",
       "      <td>1</td>\n",
       "      <td>4245</td>\n",
       "      <td>2014-12-06 02:00:00</td>\n",
       "      <td>6</td>\n",
       "      <td>Saturday</td>\n",
       "      <td>2</td>\n",
       "      <td>12</td>\n",
       "      <td>12-06</td>\n",
       "      <td>12-06 02:00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>97726136</td>\n",
       "      <td>383583590</td>\n",
       "      <td>1</td>\n",
       "      <td>5894</td>\n",
       "      <td>2014-12-09 20:00:00</td>\n",
       "      <td>9</td>\n",
       "      <td>Tuesday</td>\n",
       "      <td>20</td>\n",
       "      <td>12</td>\n",
       "      <td>12-09</td>\n",
       "      <td>12-09 20:00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>98607707</td>\n",
       "      <td>64749712</td>\n",
       "      <td>1</td>\n",
       "      <td>2883</td>\n",
       "      <td>2014-12-18 11:00:00</td>\n",
       "      <td>18</td>\n",
       "      <td>Thursday</td>\n",
       "      <td>11</td>\n",
       "      <td>12</td>\n",
       "      <td>12-18</td>\n",
       "      <td>12-18 11:00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>98662432</td>\n",
       "      <td>320593836</td>\n",
       "      <td>1</td>\n",
       "      <td>6562</td>\n",
       "      <td>2014-12-06 10:00:00</td>\n",
       "      <td>6</td>\n",
       "      <td>Saturday</td>\n",
       "      <td>10</td>\n",
       "      <td>12</td>\n",
       "      <td>12-06</td>\n",
       "      <td>12-06 10:00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>98145908</td>\n",
       "      <td>290208520</td>\n",
       "      <td>1</td>\n",
       "      <td>13926</td>\n",
       "      <td>2014-12-16 21:00:00</td>\n",
       "      <td>16</td>\n",
       "      <td>Tuesday</td>\n",
       "      <td>21</td>\n",
       "      <td>12</td>\n",
       "      <td>12-16</td>\n",
       "      <td>12-16 21:00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12256901</th>\n",
       "      <td>93812622</td>\n",
       "      <td>378365755</td>\n",
       "      <td>1</td>\n",
       "      <td>11</td>\n",
       "      <td>2014-12-13 21:00:00</td>\n",
       "      <td>13</td>\n",
       "      <td>Saturday</td>\n",
       "      <td>21</td>\n",
       "      <td>12</td>\n",
       "      <td>12-13</td>\n",
       "      <td>12-13 21:00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12256902</th>\n",
       "      <td>93812622</td>\n",
       "      <td>177724753</td>\n",
       "      <td>1</td>\n",
       "      <td>12311</td>\n",
       "      <td>2014-12-14 21:00:00</td>\n",
       "      <td>14</td>\n",
       "      <td>Sunday</td>\n",
       "      <td>21</td>\n",
       "      <td>12</td>\n",
       "      <td>12-14</td>\n",
       "      <td>12-14 21:00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12256903</th>\n",
       "      <td>93812622</td>\n",
       "      <td>234391443</td>\n",
       "      <td>1</td>\n",
       "      <td>8765</td>\n",
       "      <td>2014-12-11 16:00:00</td>\n",
       "      <td>11</td>\n",
       "      <td>Thursday</td>\n",
       "      <td>16</td>\n",
       "      <td>12</td>\n",
       "      <td>12-11</td>\n",
       "      <td>12-11 16:00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12256904</th>\n",
       "      <td>93812622</td>\n",
       "      <td>26452000</td>\n",
       "      <td>1</td>\n",
       "      <td>7951</td>\n",
       "      <td>2014-12-08 22:00:00</td>\n",
       "      <td>8</td>\n",
       "      <td>Monday</td>\n",
       "      <td>22</td>\n",
       "      <td>12</td>\n",
       "      <td>12-08</td>\n",
       "      <td>12-08 22:00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12256905</th>\n",
       "      <td>108404535</td>\n",
       "      <td>362699797</td>\n",
       "      <td>1</td>\n",
       "      <td>9847</td>\n",
       "      <td>2014-12-03 19:00:00</td>\n",
       "      <td>3</td>\n",
       "      <td>Wednesday</td>\n",
       "      <td>19</td>\n",
       "      <td>12</td>\n",
       "      <td>12-03</td>\n",
       "      <td>12-03 19:00</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>12256906 rows × 11 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "            user_id    item_id  behavior_type  item_category  \\\n",
       "0          98047837  232431562              1           4245   \n",
       "1          97726136  383583590              1           5894   \n",
       "2          98607707   64749712              1           2883   \n",
       "3          98662432  320593836              1           6562   \n",
       "4          98145908  290208520              1          13926   \n",
       "...             ...        ...            ...            ...   \n",
       "12256901   93812622  378365755              1             11   \n",
       "12256902   93812622  177724753              1          12311   \n",
       "12256903   93812622  234391443              1           8765   \n",
       "12256904   93812622   26452000              1           7951   \n",
       "12256905  108404535  362699797              1           9847   \n",
       "\n",
       "                         time  day   day_name  hour  month     md          mdh  \n",
       "0         2014-12-06 02:00:00    6   Saturday     2     12  12-06  12-06 02:00  \n",
       "1         2014-12-09 20:00:00    9    Tuesday    20     12  12-09  12-09 20:00  \n",
       "2         2014-12-18 11:00:00   18   Thursday    11     12  12-18  12-18 11:00  \n",
       "3         2014-12-06 10:00:00    6   Saturday    10     12  12-06  12-06 10:00  \n",
       "4         2014-12-16 21:00:00   16    Tuesday    21     12  12-16  12-16 21:00  \n",
       "...                       ...  ...        ...   ...    ...    ...          ...  \n",
       "12256901  2014-12-13 21:00:00   13   Saturday    21     12  12-13  12-13 21:00  \n",
       "12256902  2014-12-14 21:00:00   14     Sunday    21     12  12-14  12-14 21:00  \n",
       "12256903  2014-12-11 16:00:00   11   Thursday    16     12  12-11  12-11 16:00  \n",
       "12256904  2014-12-08 22:00:00    8     Monday    22     12  12-08  12-08 22:00  \n",
       "12256905  2014-12-03 19:00:00    3  Wednesday    19     12  12-03  12-03 19:00  \n",
       "\n",
       "[12256906 rows x 11 columns]"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import matplotlib\n",
    "import matplotlib.pyplot as plt\n",
    "import sys\n",
    "data = pd.read_csv('./data/data_clear.csv')\n",
    "data"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a1711a4f-fd41-4164-b78e-83f03982715a",
   "metadata": {},
   "source": [
    "从整体数据来看，PV,UV,平均访问量，交易总数，交易用户比例，复购率和跳失率，用户流失分析（漏斗转换）"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f40f75d-a505-45d5-90dd-7d0a74ccd9d9",
   "metadata": {},
   "source": [
    "- 'nunique()'函数是Pandas库中的一个常用方法，通常用于数据处理和分析。主要用于计算某一列或者某几列中不同（唯一）值的数量\n",
    "- 该功能在数据分析中非常有用，特别在需要了解数据集中某个特征（列）的多样性或唯一性程度时"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "3833b633-59ef-4f8d-9994-6d840a1238e7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "UV （独立访客数）: 10000\n",
      "商品数 : 2876947\n",
      "类目数 : 8916\n",
      "付费用户占比 : 8886\n",
      "付费用户占比 : 88.86%\n"
     ]
    }
   ],
   "source": [
    "r_dict = {1:'点击',2:'收藏',3:'加购物车',4:'购买'}\n",
    "data['behavior_type'] = data['behavior_type'].map(r_dict)\n",
    "#31天总用户量有操作的商品及商品类目\n",
    "total_unique_users = data['user_id'].nunique()\n",
    "#独立访问和数UV\n",
    "total_unique_itemid = data['item_id'].nunique()\n",
    "#有操作的商品\n",
    "total_unique_categoryid = data['item_category'].nunique()\n",
    "#有操作的商品类目\n",
    "user_bought_count = data[data['behavior_type']=='购买']['user_id'].nunique()  #付费用户数\n",
    "\n",
    "#输出结果\n",
    "print(f\"UV （独立访客数）: {total_unique_users}\")\n",
    "print(f\"商品数 : {total_unique_itemid}\")\n",
    "print(f\"类目数 : {total_unique_categoryid}\")\n",
    "\n",
    "print(f\"付费用户占比 : {user_bought_count}\")\n",
    "print(f\"付费用户占比 : {user_bought_count / total_unique_users * 100:.2f}%\") #计算占比单位是百分号，并且小数点后保留2位小数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "e7a9adeb-50fb-40ba-a006-cfa9a1b350d4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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3SguLsaUKVMue8zTTz+N6dOnQ61WO0b1/fbbb3jiiSeQmprq2M9iscBkMqFBgwaXPM/WrVsxZswYjBgxAsOHD6/y2IkTJxAQEHDVGRMunNfuv77//nvs3bsX2dnZV22dEbkqhhHVmqt9mr/SJ/k5c+bgxRdfxIIFC3DDDTdcdr8jR45ALpc7phz6r0OHDmH+/Pn4+eef8e2336J///4AKkNl/Pjx+P777/Hkk09ixIgRji49s9mMI0eOQKvVVunmAyonf7XZbI7utQvl5uZCpVKhVatWAICioiJ89NFHmD17Nvr06YOff/7Zse+5Ofu+++479OzZ87Kv7xyZTFblepDdbnf8fLOysrB48WLcf//96Nev31XPReSSpB0/QZ7swmHRF0pJSREzZ84UvXv3FjqdrspjBQUFYsSIEQKAmDVr1iXPu3XrVvHCCy+IJ554QgQGBoqBAwdWefzw4cNiypQponXr1gKAGDp0qDh48OBF58nKyhJTp04VcrlcBAYGiieeeEIIIURaWppQKBRCp9MJf3//an9ptVrRq1cvx/mnTZsmdDqdmDNnjrBYLFWee8mSJSIiIkLcfffdjmHn1+KTTz4RTZo0EUKcv1mXyJ3JhKhGZzTRdVAqlfjxxx8xfvz4ix7r1KkT5HI5HnjgATz00EOO7UIITJs2DR07dsT//d//XfK8aWlpaN26NcLDw9G3b1/MmjWrSjedXq/HhAkT0L17d4wbNw6xsbFXrDMlJQXffvst+vXrh5tvvvk6X+3FbDYbsrOzr9qFeD3mz5+Pt956C1lZWU4/N5EUGEZERCQ53mdERESSYxgREZHkGEZERCQ5hhEREUmOYURERJJjGBERkeQYRkREJDmGERERSY5hREREkmMYERGR5BhGREQkOYYRERFJjmFERESSYxgREZHkGEZERCQ5hhEREUmOYURERJJjGBERkeQYRkREJDmGERERSY5hREREkmMYERGR5BhGREQkOYYRERFJjmFERESSYxgREZHkGEZERCQ5hhEREUmOYURERJJjGBERkeQYRkREJDmGERERSY5hREREkmMYERGR5BhGREQkOYYRERFJjmFERESSYxgREZHkGEZERCQ5hhEREUmOYURERJJTSl0AUW0zWmzILTUht8yIvDIT8vQm5OvNsNrsAABxdj9x9i8Cjr/853EBlUKOAJ0KATo1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dSByawwjqlPJuWVYn5CLTSfysDe1CCYrBz9Ul1wGdIwJwKCWoRjQIhRto3gNiDwHw4gkY7TYsP90EbadzMe25AIcySiBjWtbVBGoU+GG2BAMahmK/nEhCPRWS10SUa1gGJHLKDVasDulEIczSpCQVYqE7DKkFZXXmxttg300aBPph7ZRfmgT6Y+2kf6IaeAFmYyrp5LnYxiRS9ObrEjMLkV8VhnizwZUYnYZ9Car1KXVSFSA19ng8XeETxjngqN6jGFEbkcIgbTCCsRnlyLhbEilFhiQrzejqNzsMl193moFIgK8EBnghUh/LZoEe6NtlD/aRPohQMfuNqILMYzIo9jtAkXlZhQYzMjXm1CgP/9ngcGEfL0ZBfrKPwsNZlhsdshkgFwmgwxn/5QBMpkM8gv+BM59DyjlcjTwVqOBtxpB5/700SDIW41gXzUi/CsDiHO9EVUfw4iIiCQnl7oAIiIihhEREUmOYURERJJjGBERkeQYRkREJDmGERERSY5hREREkmMYERGR5BhGREQkOYYRERFJjmFERESSYxgREZHkGEZERCQ5hhEREUmOYURERJJjGBERkeQYRkREJDmGERERSY5hREREkmMYERGR5BhGREQkOYYRERFJjmFERESSYxgREZHkGEZERCQ5hhEREUmOYURERJJjGBERkeQYRkREJDmGERERSY5hREREkmMYERGR5BhGREQkOYYRERFJjmFERESSYxgREZHkGEZERCQ5hhEREUmOYURERJJjGBERkeQYRkREJDmGERERSY5hREREkmMYERGR5BhGREQkOYYRERFJ7v8BW909Bbx2XL0AAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "plt.rcParams['font.sans-serif'] = 'SimHei'\n",
    "#计算行为类型的分布\n",
    "type_series = data['behavior_type'].value_counts()\n",
    "\n",
    "#绘制饼图\n",
    "plt.figure()\n",
    "plt.pie(x=type_series, labels=type_series.index, autopct='%1.2f%%')\n",
    "plt.title('行为类型分布')  #同样还可以添加一些特殊的设置\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "81c6e9a3-fb00-4b84-b797-69975fecde30",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "behavior_type\n",
       "点击      11550581\n",
       "加购物车      343564\n",
       "收藏        242556\n",
       "购买        120205\n",
       "Name: count, dtype: int64"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#计算行为类型分布\n",
    "type_series = data['behavior_type'].value_counts()\n",
    "type_series"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "fa8e79c1-f62d-4952-ad54-9761a4a6e4c3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>点击</th>\n",
       "      <th>加购物车</th>\n",
       "      <th>收藏</th>\n",
       "      <th>购买</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>total</th>\n",
       "      <td>1.155058e+07</td>\n",
       "      <td>343564.000000</td>\n",
       "      <td>242556.000000</td>\n",
       "      <td>120205.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>avg_day</th>\n",
       "      <td>3.725994e+05</td>\n",
       "      <td>11082.709677</td>\n",
       "      <td>7824.387097</td>\n",
       "      <td>3877.580645</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>avg_user</th>\n",
       "      <td>1.155058e+03</td>\n",
       "      <td>34.356400</td>\n",
       "      <td>24.255600</td>\n",
       "      <td>12.020500</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                    点击           加购物车             收藏             购买\n",
       "total     1.155058e+07  343564.000000  242556.000000  120205.000000\n",
       "avg_day   3.725994e+05   11082.709677    7824.387097    3877.580645\n",
       "avg_user  1.155058e+03      34.356400      24.255600      12.020500"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#9月内各个行为的操作总数，每日平均操作数，每日平均操作用户数记录\n",
    "type_df = pd.DataFrame(\n",
    "    {\n",
    "        'total': type_series.to_list(),\n",
    "        'avg_day': (type_series / 31).to_list(),\n",
    "        'avg_user': (type_series / total_unique_users).tolist()\n",
    "    },\n",
    "    index=['点击', '加购物车', '收藏', '购买'],\n",
    ").T\n",
    "type_df\n",
    "# .T\n",
    "# 原始DataFrame\n",
    "#   A B C\n",
    "# 0 1 4 7\n",
    "# 1 2 5 8 \n",
    "# 2 3 6 9\n",
    "\n",
    "#转置后 DataFrame\n",
    "#   0 1 2\n",
    "# A 1 2 3\n",
    "# B 4 5 6\n",
    "# C 7 8 9\n",
    "# <style>\n",
    "# .dataframe tbody tr th {\n",
    "#     vertical-align: top;\n",
    "# }\n",
    "# .dataframe thead th {\n",
    "#     text-align: right;\n",
    "# }\n",
    "# </style>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f5518618-2dfd-4860-a06f-b4e1cd5b9561",
   "metadata": {},
   "source": [
    "'isin()'函数是Pandas库中的一个函数，用于检查DataFrame或Series中的元素是否存在于指定的列表中。他返回的是一个布尔值的Series或DataFrame.其中每个元素表示该位置的值是否在给定的列表中"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "a77284cf-7a85-4e71-8c32-c02124380f23",
   "metadata": {},
   "outputs": [],
   "source": [
    "#付费用户行为记录\n",
    "paying_user_type_series = data[data['user_id'].isin(data[data['behavior_type']=='购买']['user_id'])]['behavior_type'].value_counts()\n",
    "type_df.loc['paying_user'] = paying_user_type_series"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1da32d73-a5e4-4a32-bc1b-f695ba8ea023",
   "metadata": {},
   "source": [
    "### 跳失率和复购率\n",
    "- 跳失率=只有点击行为的用户/总用户数\n",
    "- 其实真正的跳失率应该是只浏览一个页面就离开的访问次数/该页面的全部访问次数，这边只是了突出这些有待发展的客户\n",
    "- 复购率=购买2次及以上用户数/总购买用户数\n",
    "- 复购率可以分为按客户计算和按交易计算，这里采用的是按客户计算，一定要确定统计周期，像这个数据的统计周期就是9天"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8006fc0c-983f-42ea-973d-5c4f1570e20c",
   "metadata": {},
   "source": [
    "> 此外，针对于复购率还会有专门的模块进行整体项目的编写"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "8af858ce-7551-48de-ba0f-e5bd4577c1a5",
   "metadata": {},
   "outputs": [],
   "source": [
    "#计算总用户数\n",
    "total_unique_users = data['user_id'].nunique()\n",
    "\n",
    "#只有点击行为的用户数\n",
    "click_only_users = data[data['behavior_type']=='点击']['user_id'].nunique()\n",
    "\n",
    "#计算跳失率\n",
    "#跳失率=只有点击行为的用户/总用户数\n",
    "bounce_rate = click_only_users / total_unique_users\n",
    "\n",
    "#计算购买用户数\n",
    "buy_users = data[data['behavior_type']=='购买']['user_id'].nunique()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "44424249-2f3e-43ff-91a7-4bc394c397bc",
   "metadata": {},
   "outputs": [],
   "source": [
    "#计算购买2次及以上的用户数\n",
    "groupby_userid = data.groupby('user_id')\n",
    "user_buy_counts = groupby_userid.size()\n",
    "repeat_buy_users = user_buy_counts[user_buy_counts >= 2].index.nunique()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "3f0834f9-b17f-4039-81e8-a17c27139886",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "跳失率: 1.00\n",
      "复购率: 1.12\n"
     ]
    }
   ],
   "source": [
    "#计算复购率\n",
    "#复购率=购买2次及以上用户数/总购买用户数\n",
    "repeat_purchase_rate = repeat_buy_users / buy_users\n",
    "\n",
    "#输出跳失率和复购率\n",
    "print(f\"跳失率: {bounce_rate:.2f}\")\n",
    "print(f\"复购率: {repeat_purchase_rate:.2f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "5111f10b-a1cc-4d45-bc97-ce7e4510fc3d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "跳失率: 0.0004000%\n"
     ]
    }
   ],
   "source": [
    "#计算总用户数\n",
    "total_unique_users = data['user_id'].nunique()\n",
    "\n",
    "#对每个用户的行为类型进行比较\n",
    "user_type = data.groupby('user_id')['behavior_type'].value_counts().unstack(fill_value=0)\n",
    "\n",
    "#标记中只点击行为的用户\n",
    "only_click_users = user_type[user_type['点击'] == 1].index\n",
    "\n",
    "#计算跳失率\n",
    "bounce_rate = len(only_click_users) / total_unique_users\n",
    "\n",
    "#输出跳失率\n",
    "print(f\"跳失率: {bounce_rate:.7f}%\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b556a21-0740-4f1b-814c-54f2097e7966",
   "metadata": {},
   "source": [
    "分析：跳失率为0.00%，数值看上去比较小，但跳失率一定程度上反映了商品的受欢迎程度，最好还是结合行业数据和以往的数据分析是否处于正常范围"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0b079c1c-d9a7-4497-868d-e85224b68742",
   "metadata": {},
   "source": [
    "影响跳失率的因素：商品吸引力、商品加载时长等"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "e54444c5-6309-4c43-81da-15ffdfa85a81",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "复购率: 91.69%\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjwAAAHECAYAAAA9JvBzAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA+6ElEQVR4nO3deVxUZd/H8e8ww5oLYGSFqKjdlpml3Chhej8VaXepaZukbZpLampPRWnZfqdUammLZmJoZWWLmpoauWULFqUUN2SWkmhWLsjiwLBdzx++mMcJRDSJ8fB5v17nFee6zpm5fjMmX8+5zjk2Y4wRAACAhfnU9wAAAADqGoEHAABYHoEHAABYHoEHAABYHoEHAABYHoEHAABYHoEHAABYHoEHAABYHoEHAABYHoEHwAkrLS3Vtm3bjnu/pUuX6uDBgyd1LElJSfryyy9PaN8ZM2bovvvuU1lZWa332bVrlz766KMq7du3b1dJSUmtX8flcrl/Nsbo008/VV5eXq33r/Tiiy8qMTHxuN4baEgIPEADsWrVKtlstlov77zzzjFf88EHH1RcXJxKS0trPY7PPvtMN95443GHk8mTJ+vuu+/2WB566CFJh4PCo48+qk2bNh11f2OMnnnmGWVnZ1fpe+utt/Tbb7/J4XDUOIZdu3YpJiZGu3fv1meffaahQ4dKku666y5NmzZNkjRq1CgNGjSoVjVVVFSoa9euevbZZyVJTqdT1157rV5++eVa7X+kF154QevWrZOfn99x7ws0BAQeoIHw9fWVJBUVFbmXDz74oEpbYWGhJCkgIOCYrzlmzBjl5OTovffeq9UY9uzZo/j4eJWVlemGG25Qo0aNql2CgoJkt9uVmprq3nfhwoXKycnR6aefrtNPP11Op1Pz5s2TJH355ZfKy8vTHXfccdT3Li4u1ptvvqkBAwaoqKjI3f7TTz/pq6++UkJCwjHH36JFC3Xt2lVDhw6Vn5+f/Pz8tHfvXi1YsEBXXnmlJGnLli3q169frT6P999/X999951iY2MlSaeddpomTpyop59+Wjk5OdXu43Q6VVhY6BEyP/nkE/344496+OGHq2xvjFFpaany8/NrNSbAqmr+5wwAy6g8enFkkKkMQUe2VZ7WqeyrVFJSou3bt1d53QcffFChoaH64YcfPNobN26s8PBw9/qOHTvUq1cvxcTEKDk5ucajKRUVFSoqKlKTJk08xt+3b19ddtllcjgc2r59u1auXClJSk5OVmFhocf2lT7//HPFxsYqMDBQixcvVlRUlEaNGqXk5GRJ0uzZs2WM0UUXXVTtWJKSktxHcr744gtddNFFatOmjb766isVFxdr+fLl6tevn7799luVl5dr7969+ve//+3ev7S0VMaYKkdeSkpK9Nhjj6l///7q3r27u33s2LGaO3eubrvtNqWkpMhut3vsN3r0aM2fP7/asfbo0eMon+hhRUVFtQqygCUZAA3Cp59+av78v/yyZcuqtJWWlhpJZuXKlR7tmZmZRlKtlxtuuMG977x580zTpk3NsGHDTFhYmPHx8TF2u73axcfHx5x33nlVxt+lSxfz2muvmaFDh5rLL7/cbNy40bRs2dLs3bvXBAUFmY8//tjk5OS4l6ysLCPJpKWlebzOokWLjCTz/vvvm71795rGjRubV155xezZs8djmT17trHb7Wbv3r3ufadMmWJ69uxpunTpYiSZgIAA06tXLxMXF2d69Ohhnn766Wo/iyeffLJKPQ888IDx9/c327Ztq9K3adMm4+fnZ2677TZTVlbm0bd7927z448/ml9++cXs2bPHzJo1y9jtdrN+/XqTmZlpnnvuObN169Yq9ezZs6fK+wANCYEHaCA2btxoJBl/f3/34uvrW6XN39+/2sCzbds2I8ns2LHjmO914YUXmsGDB7vXV61aZZ555hljjDHNmzc3KSkpR933tddeM507d67SXhl4Ro4caQYNGmQ2btxoWrVqZYYPH26uueYa88svvxin0+ne/sCBA0aS2bx5c5XXmj17tnE6nWb06NGmY8eOpry83Pzwww9mzpw55o8//jDGGHPbbbeZHj16VNn34MGDJjY21rRv3960bNnSTJ482fz3v/91133fffeZgoICU1BQYM455xwzd+5cU1hY6PEa69atM3a73UyfPv2on8Pbb79tHA6HueKKK44aVg4ePGjCw8PN3XffbYwxJiMjo9bfEdDQMIcHaCCMMZIOz2WpXCrn8BzZVjmH58+ONaH3z448FdO7d2+POTK9e/eWw+Godrnjjjvk41P1ryabzeYeR1BQkLv9+uuv1+TJkzVlyhRdddVV7vbKU3N/PiUkSSNHjtS+ffu0aNEivfDCC/Lx8dGOHTs0YsQI5efnyxij9evX67rrrvPYb9OmTYqJiVF4eLiefPJJlZWVqWnTprriiiu0ZMkSpaenq6yszD0X6ffff1erVq102mmnuV8jPT1d1157rXr27Kmrr75aO3fu1K5du6os3bt315w5c/TVV1+pQ4cOWrBggcdYysvLNWjQIIWGhmrKlCmS/v80pL+//zG+HaDhYQ4P0EBUVFT8pf0rg0PlpNljvVdlQKmub/Xq1YqLi6u2Pzk5WTNnzqzSXhnYJCk4ONj9c69evSRJGzZs0BNPPCFjjCoqKlReXi6p6lwkSfrvf/+rc889V9u3b1fjxo0lyX05d/PmzWWz2bRjxw73a0iH5+LMnDlT8fHxeuSRRzRr1iz16tVLo0ePlp+fn1599VUFBwdry5Ytkg5/Tvn5+YqMjHS/RlFRkfr376927dpp0KBBat++fbWfQaXu3bvr66+/1i233KLzzz/f47MYNWqU+7L4wMBAj/3OPvtsj/XBgwfrjTfeqPG9AKsj8AANROVVPUeGleLi4iptR/6SP1Ll/WKO/MVbk6NNAi4tLdWVV16p8vLyao++SFKHDh2qtFUGtsLCQvcv9Mq2LVu2qLi4WAMGDFBMTIwSEhIUExMjqeqRqbKyMvXv31/9+vVzX0ouHb5aS5Kys7PVsWNH2Ww2j319fX01e/Zs+fj46Oeff9aYMWOUkpKisrIy3XLLLVqxYoVefPFFDRs2TC6XS1u3blVQUJBat27tfo3AwECtWbNGwcHBCgwM1IABAyQdDlmvvPKKBg4c6N72+uuv1+mnn65zzjnH42o1l8ulO+64Q++++6769OmjnTt3asWKFe6x9+jRQ99++63CwsIkSePGjeOIDyACD9BgOJ1OSXIf0ThSdW1/tn//fkmHLwFv0aJFjdvedNNNR72JX25uru677z6tXr1aaWlptf5lXBlusrOzdfHFF0v6/9NWTzzxhO655x7Z7XZFRUVpyZIlio6OllQ18Lz++uvKycnRqFGjPNo/+eQT2Ww2ffDBB+rYsWO1Y+jRo4fS09Pd61dccYX75+TkZA0ePFiTJk3Sxx9/rJ07d6pbt25VQl2bNm3cPwcGBiojI0Pl5eWKiopSo0aN3H2///67unTp4rFvWVmZLr/8cn3zzTd6//339dNPP+mNN95wfx+VAfass87SmWeeKUkKCgqq9igX0NAwhwdoIH777Tc1a9ZM5vDFCjLGaNmyZZLk0Xa0mwj++uuv8vPz0z//+U+1aNGixmXMmDG64YYbqn2dpKQkPffcc8rKytJpp53mMX/Hx8dHPj4+WrduXZX9SktLVVZWpi1btqhjx44KCAjQmWeeqfXr12vx4sWaMWOGmjdvrldffVUrVqxw//I/MvA4nU498cQTuv/++9WuXTt3e1ZWllJSUvTSSy/pueee0549e6od+/r167V//35FRETo7bffVlFRkdatW6fAwEBdc801kqSbb75ZM2bM0KJFi4562u5IS5cuVbNmzdSpUyeP9l27dikiIsKjzeFw6JlnntHq1avVp0+fY742gP/HER6ggcjKyqr16ajqfPnll7rgggtqNXk5Pj6+SpvL5dLDDz+sl19+WUOGDFF6erqWLFnivlfPL7/8ou7du2vYsGG69NJLq+w/d+5cZWVlyWaz6ayzzpLdbte3336r0tJS/e///q969uypjh07KjAwUBdeeKG2bt0qyXMOz8SJE1VRUaEJEya424qKinTrrbfqxhtvdM+L6dOnjz755BOFhIR4jCE4OFgvvviifvvtN+3atUuZmZmaPHmyRo8e7Z5XNGbMGPedkxctWlTj5/THH3/o+eef1+233+4xUdvlcrmD1Z9V3qRQ8pzXdDR/de4WYBUc4QEaiDVr1uhf//rXCe1bUVGh9957T3379j3h958yZYreffddrVu3Tk8//bTCwsIUFRWlt956S2lpabr00kt1880367HHHqt2/4svvljz5s3TrbfeqsmTJ6tnz57avXu3fH19NX36dPdk4PDwcP3222/uIziVAe3999/XzJkzNXXqVPdVXnv37lWvXr1UXFzsfpxDUlKSDhw4oNjYWGVlZVUZx6233qp3331XO3fuVM+ePZWSkqLt27dr8+bNkg6fVmrSpIkaNWqkgoKCo34ev/76q3r37q2goCBNmjTJo2/btm0yxlQbeI505HO4/mz9+vV68MEHlZKS4p7PAzRkBB6gAUhLS9P333+v66+/3qO9coJy5VGA8vJy7dq1S5I87gw8b9487d69WyNHjjzhMTz66KPKyMhQdHS0mjVrphUrVmjgwIEaNGiQunbtqvPOO0/jx48/6v5PPvmktm7dqkceeUTTpk1TaGio+vXr5/GYiEoOh0NfffWVfH193fNi9u3bp7i4ON1www0qLy/X/Pnzdf7558vpdGrVqlVq2rSp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at68+VHHd9ddd8nPz09Op1PnnXeevvvuO11yySXq16+fzjrrLO3bt8/jie0AvBOBB0C9+fLLLzV48GCdc845GjBgwFG3+9e//qXzzjtPkuTr66sDBw7o888/V4sWLTR69GgtWbJErVu39ghMJSUluvjii7V69WpJ0ueff67evXtr7dq16tq1q6ZNm6YHHnhAwcHBHu9ls9n09ddfq3Xr1tq1a5fWr1+vAwcOKCUlRRERESosLFTv3r3l5+enGTNm6LPPPpN0+KGKxhj3gyIBeBdOaQGoF4WFhbr77rv14osvyuVy6ddff1WjRo2qLAsXLtRXX33l3s/Hx0e///67Bg4c6F6fOXOmhg8frn379rmXWbNmyd/f371f9+7ddf/992vChAkqKirStGnT9Pnnn3vsM3v2bIWFhal169aSpD179uiTTz7RwoULtXz5cmVkZCggIECffPKJli1bph9//FHt2rVTs2bNFBYWpgULFvytnyGA2nPU9wAANEyNGjXSpk2bJEnPPPOM3njjDQUFBVXZbvfu3bLb7e51m80mPz8/92mkiooKffXVV3rhhRd04403asGCBQoICFB5ebnHfpI0YcIEjR8/XpMmTdIll1yibt26KTExUeXl5XrooYe0dOlSXXPNNe7to6OjNWzYMA0bNkyXX365WrdurYMHDyopKUktWrTQ+++/r7i4OE2YMEHBwcG644476uKjAnASEHgA1Lvy8nKNGTNG559/fpW+adOmqaKiwr1ujJHD4XAHHh8fH3300Udavny5Dh06pICAAEmHTzH9+fSSn5+f7Ha7rrjiCnXo0EHS4UBVeSTo2muvVadOndzbz58/X88++6yWLFmil19+Wf/4xz/0888/a9SoUSosLNRPP/2kuLg47dmzp9qxA/AeBB4A9e7OO+/UvHnz9NZbbyk+Pt6jr3fv3urcubN7vaKiQoWFhQoJCXGvS9LChQt1//33a+zYserVq1e1geeHH37QjTfeqLS0NPd8n927d6tZs2aSVGUe0XXXXadrrrlG33//vb7++ms999xzstvtGjFihO655x599tlnuvPOO7Vjxw61b9/+5H4oAE4qAg+Aenfuuefqm2++UZMmTZScnOzR16JFC40bN869Xl5eru3bt7uvrCopKdHnn3+u77//XoGBgSotLdX777+vrl27yuHw/Cvu8ccf1yWXXOIOO2VlZfrss88UGBiosrKyKtvPnj1bL7zwgvbu3avg4GC1b99ee/bs0WOPPaaRI0fq3HPP1cGDB5WZmamLLrro5H8wAE4aJi0DqDfGGM2dO1fXXnutBgwYoEsuuURpaWnKyMjQkiVLlJ+fr4cfftgdUMrLy9WrVy+tXbtW//znP3X22WdrwoQJ+uabb3To0CFNmzZNfn5+Wr58uVwul8cRnq+++kpr167VU0895W5LSkpS165dddlll+npp5+uMr777rtP3377rc444wxlZWXp+++/V0hIiOLj49WkSRNdeumluvbaa9WjR4+jXlIPwDtwhAdAvfnjjz+0fv16rV27VmeddZbGjh2riy66SKNGjdKsWbO0YMECde/e3b293W7X+++/r7Zt22rKlCmKj4/Xhx9+KF9fX4+jQNdee62++eYb9xGbQ4cO6fbbb9fjjz/uPhX2xRdf6JFHHtEnn3yisLAwdenSRY0bN/Z4HUn67rvv1KJFC/Xq1UunnXaaLrzwQoWHh0uShg8frksvvVRLliyp408KwF/FER4A9aZ58+aaP3++fH199cUXX6ht27YqLCzU9OnT5XK5tGLFCr311lvauHGjfvrpJ7lcLo0ePVoDBgzQoEGDVFZWpiFDhlS5Gut//ud/tH37dvfE5lmzZsnPz0/Dhw9XRUWFXnjhBfXp00dJSUm64IILdOaZZ2r16tV6/PHHNXjwYP3666/u17r00ku1du1axcbG6tChQ5IOzznatm2bxo8fryuvvFL33ntvjXeJBlD/CDwA6s2IESPUtGlT9evXT/Pnz1ezZs20adMm/fLLL1qxYoVatWqlVatWafz48YqJidHzzz+vjIwMPfvss/L399e7776rvLw85efnu18zLS1NgYGBeu+993TTTTdJku69914tX75cdrtdV111lV588UWlpKSoT58+7v0uuOACpaam6scff9TNN98sY4y2b9+uiRMn6oILLlBQUJA2bNig9957T02bNlWPHj00ceJErVy5Utddd506d+6slJSUv/0zBFA73GkZQL0pLS097jsT5+fnH/NRDpmZmWrfvn2VIz/S4auyTj/9dI+bEh6pvLxceXl5Cg0NVVFRkZKSkhQfH6/TTz/dvc28efN09dVXezySYvXq1brsssu40zLgpQg8AADA8jilBQAALI/AAwAALI/AAwAALI/AAwAALI/AAwAALI/AAwAALI/AAwAALI/AAwAALO//AIsLZ4TzVjKfAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import seaborn as sns\n",
    "#计算总购买用户数\n",
    "user_bought_count = data[data['behavior_type'] == '购买']['user_id'].nunique()\n",
    "\n",
    "#对每个用户的行为类型进行计数\n",
    "user_type = data.groupby('user_id')['behavior_type'].value_counts().unstack(fill_value=0)\n",
    "\n",
    "#计算复购用户数，即购买记录超过1次的用户数\n",
    "repurchase_users = user_type[user_type['购买'] >= 2].shape[0]\n",
    "\n",
    "#计算复购率\n",
    "repurchase_rate = repurchase_users / user_bought_count\n",
    "\n",
    "#输出复购率\n",
    "print(f\"复购率: {repurchase_rate * 100:.2f}%\")\n",
    "\n",
    "#进一步分析复购率\n",
    "sns.histplot(user_type[user_type['购买'] >= 2]['购买'] - 1, kde=False)\n",
    "plt.xlabel('复购次数')\n",
    "plt.ylabel('用户数')\n",
    "plt.title('用户复购次数分布')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6548febe-2f5f-40e2-917d-9a17761dc14c",
   "metadata": {},
   "source": [
    "- 结论：淘宝用户复购率能达到66.1%，但是进一步查看用户复购次数，发现绝大多数用户复购次数给很少\n",
    "- 推测：淘宝的市场份额一直稳居前列，用户量足够大，足够的用户量复购一次也能提高复购率\n",
    "- 个人思考：在淘宝下沉扩展获取新用户的同时，促进老用户复购次数增加，进一步稳提高复购率影视更重要的事情。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "c4e6a49e-79f8-4c42-95d5-a135fc128100",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{1: '点击', 2: '收藏', 3: '加购物车', 4: '购买'}"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "r_dict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "1fcf1ba6-55d3-4f25-88a5-a1fd6e101ad7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "点击到收藏的转化率: 67.30%\n",
      "点击到加购的转化率: 86.14%\n",
      "收藏到购买的转化率: 132.04%\n",
      "加购到购买的转化率: 103.16%\n"
     ]
    }
   ],
   "source": [
    "#根据行为类型筛选数据\n",
    "pv_df = data[data['behavior_type'] == '点击']\n",
    "buy_df = data[data['behavior_type'] == '购买']\n",
    "cart_df = data[data['behavior_type'] == '加购物车']\n",
    "fav_df = data[data['behavior_type'] == '收藏']\n",
    "\n",
    "#计算每步的用户数\n",
    "pv_users = pv_df['user_id'].nunique()\n",
    "fav_users = fav_df['user_id'].nunique()\n",
    "cart_users = cart_df['user_id'].nunique()\n",
    "buy_users = buy_df['user_id'].nunique()\n",
    "\n",
    "#计算转化率\n",
    "pv_to_fav_rate = fav_users / pv_users if pv_users > 0 else 0\n",
    "pv_to_cart_rate = cart_users / pv_users if pv_users > 0 else 0\n",
    "fav_to_buy_rate = buy_users / fav_users if fav_users > 0 else 0\n",
    "cart_to_buy_rate = buy_users / cart_users if cart_users > 0 else 0\n",
    "\n",
    "#输出转化率\n",
    "print(f\"点击到收藏的转化率: {pv_to_fav_rate:.2%}\")\n",
    "print(f\"点击到加购的转化率: {pv_to_cart_rate:.2%}\")\n",
    "print(f\"收藏到购买的转化率: {fav_to_buy_rate:.2%}\")\n",
    "print(f\"加购到购买的转化率: {cart_to_buy_rate:.2%}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "383714f2-9f06-4eaf-821f-1651a76b87f7",
   "metadata": {},
   "outputs": [],
   "source": [
    "#针对以上都转化率数据操作进行可视化\n",
    "from pyecharts.charts import Funnel\n",
    "from pyecharts import options as opts\n",
    "import pandas as pd\n",
    "\n",
    "#根据行为类型筛选数据\n",
    "#根据行为类型筛选数据\n",
    "pv_df = data[data['behavior_type'] == '点击']\n",
    "buy_df = data[data['behavior_type'] == '购买']\n",
    "cart_df = data[data['behavior_type'] == '加购物车']\n",
    "fav_df = data[data['behavior_type'] == '收藏']\n",
    "\n",
    "#由于此处存在2个DataFrame.所以这里要使用merge进行合并操作，同concat的使用方式非常像\n",
    "# process1 点击->加购->购买\n",
    "pv_cart_df = pd.merge(left=pv_df,   #指定左侧的DataFrame,即pv_df\n",
    "                     right=cart_df,   #指定右侧的DataFrame,即cart_df\n",
    "                     how='inner',   #内连接，只保留两个DataFrame都存在的记录\n",
    "                     on=['user_id', 'item_id'],   #指定合并的键，即user_id和item_id\n",
    "                     suffixes=('_pv', '_cart'))   #对于重命名的列，添加后缀\n",
    "cart_buy_df = pd.merge(left=cart_df,\n",
    "                      right=buy_df,\n",
    "                      how='inner',\n",
    "                      on=['user_id', 'item_id'],\n",
    "                      suffixes=('_cart', '_buy'))\n",
    "\n",
    "count_users_pv_cart = pv_cart_df[pv_cart_df['time_pv'] < pv_cart_df['time_cart']].user_id.nunique()\n",
    "count_users_cart_buy = cart_buy_df[cart_buy_df['time_cart'] < cart_buy_df['time_buy']].user_id.nunique()\n",
    "\n",
    "# process2 点击->收藏->购买\n",
    "pv_fav_df = pd.merge(left=pv_df,\n",
    "                    right=fav_df,\n",
    "                    how='inner',\n",
    "                    on=['user_id', 'item_id'],\n",
    "                    suffixes=('_pv', '_fav'))\n",
    "fav_buy_df = pd.merge(left=fav_df,\n",
    "                     right=buy_df,\n",
    "                     how='inner',\n",
    "                     on=['user_id', 'item_id'],\n",
    "                     suffixes=('_fav', '_buy'))\n",
    "count_user_pv_fav = pv_fav_df[pv_fav_df['time_pv'] < pv_fav_df['time_fav']].user_id.nunique()\n",
    "count_user_fav_buy = fav_buy_df[fav_buy_df['time_fav'] < fav_buy_df['time_buy']].user_id.nunique()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "ba95f229-6eea-4270-9d8b-6e0e752c5f1e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'D:\\\\jupyter\\\\淘宝用户购物行为数据分析\\\\漏斗图2.html'"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#漏斗图数据对\n",
    "process1_data_pair = [\n",
    "    ('点击量', total_unique_users),\n",
    "    ('加购量', count_users_pv_cart),\n",
    "    ('购买量', count_users_cart_buy)\n",
    "]\n",
    "\n",
    "process2_data_pair = [\n",
    "    ('点击量', total_unique_users),\n",
    "    ('加购量', count_user_pv_fav),\n",
    "    ('购买量', count_user_fav_buy)\n",
    "]\n",
    "\n",
    "#绘制漏斗图\n",
    "funnel1 = (\n",
    "    Funnel(init_opts=opts.InitOpts(width='500px', height='400px'))\n",
    "    .add(\"转化过程\",\n",
    "        data_pair=process1_data_pair,\n",
    "        label_opts=opts.LabelOpts(position='inside'),\n",
    "        gap=2,\n",
    "        tooltip_opts=opts.TooltipOpts(is_show=True))\n",
    "    .set_global_opts(title_opts=opts.TitleOpts(title=\"用户转化率\", subtitle=\"点击->加购->购买\"))\n",
    ")\n",
    "\n",
    "funnel2 = (\n",
    "    Funnel(init_opts=opts.InitOpts(width='500px', height='400px'))\n",
    "    .add(\"转化过程\",\n",
    "        data_pair=process2_data_pair,\n",
    "        label_opts=opts.LabelOpts(position='inside'),\n",
    "        gap=2,\n",
    "        tooltip_opts=opts.TooltipOpts(is_show=True))\n",
    "    .set_global_opts(title_opts=opts.TitleOpts(title=\"用户转化率\", subtitle=\"点击->收藏->购买\"))\n",
    ")\n",
    "\n",
    "funnel1.render('漏斗图1.html')\n",
    "funnel2.render('漏斗图2.html')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "cde7102c-ca5a-4e89-aadd-5db4cfe611d0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "收藏加购用户转化率为:111.82%\n",
      "购买用户转化率为:79.94%\n"
     ]
    }
   ],
   "source": [
    "fav_cart_ratio = (count_user_pv_fav + count_users_pv_cart) / total_unique_users\n",
    "buy_ratio = (count_user_fav_buy + count_users_cart_buy) / total_unique_users\n",
    "print('收藏加购用户转化率为:%.2f%%' % (fav_cart_ratio*100))\n",
    "print('购买用户转化率为:%.2f%%' % (buy_ratio*100))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9592d896-98e4-4de5-9658-e80d06629922",
   "metadata": {},
   "source": [
    "## RFM分析"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "00041a3c-d385-4cc1-be35-93a9202dc17a",
   "metadata": {},
   "source": [
    "用户价值分析——RFM分析，RFM模型通过一个客户近期的购买行为，购买的总体频率以及花了多少钱3项指标来描述客户的价值状况"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a7e090cf-413e-4345-b057-d695ecb39487",
   "metadata": {},
   "source": [
    "- R (Recency): 客户最近一次交易时间的间隔，R值越大，表示客户交易的时间越久，反之，则表示客户交易发生的日期越近\n",
    "- F (Frequancy): 客户在最近一段时间内交易的次数，其中F值越大，表示客户交易越频繁，反之则表示客户交易不够活跃\n",
    "- M (Monetary): 客户在最近一段时间内交易的金额，M值越大，表示客户的价值观越高，反之则表示客户的价值观越低"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "51140f45-9e6c-42fc-bdb9-ce7713885ab1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "count                         12256906\n",
       "mean     2014-12-04 04:47:28.445699072\n",
       "min                2014-11-18 00:00:00\n",
       "25%                2014-11-26 15:00:00\n",
       "50%                2014-12-04 14:00:00\n",
       "75%                2014-12-11 23:00:00\n",
       "max                2014-12-18 23:00:00\n",
       "Name: time, dtype: object"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data['time'] = pd.to_datetime(data['time'])\n",
    "data['time'].describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "ac7cba8a-bf8f-448a-aa44-1802b9d235bb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Timestamp('2014-11-18 00:00:00')"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data['time'].min()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "bbddc3ae-33e7-4fe2-93c6-1fa77cb1157f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Index(['user_id', 'item_id', 'behavior_type', 'item_category', 'time', 'day',\n",
       "       'day_name', 'hour', 'month', 'md', 'mdh'],\n",
       "      dtype='object')"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.columns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "fdb5d34e-32ca-4ba3-b0b8-5d3bedf57a25",
   "metadata": {},
   "outputs": [],
   "source": [
    "latest_date = data['time'].max() + pd.Timedelta(days=1)  #假设分析的“现在”是数据中的最后一个日期的次日\n",
    "data['recency'] = (latest_date - data.groupby('user_id')['time'].transform('max')).dt.days"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "2cba4ba9-1560-4db7-8125-8073213e9305",
   "metadata": {},
   "outputs": [],
   "source": [
    "data['frequancy'] = data.groupby('user_id')['time'].transform('count')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "23d63c66-52dc-4925-87b8-66cf4a7dde93",
   "metadata": {},
   "outputs": [],
   "source": [
    "#只有购买行为时设置为1，其他行为为0\n",
    "data['monetary'] = (data['behavior_type'] == '购买').astype(int)\n",
    "data['monetary'] = data.groupby('user_id')['monetary'].transform('sum')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "7b998b69-41b0-44ac-8538-0c4f04d41686",
   "metadata": {},
   "outputs": [],
   "source": [
    "rfm = data.groupby('user_id').agg({'recency': 'min', 'frequancy': 'max', 'monetary': 'max'}).reset_index()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "3c13d26d-02f2-4688-a049-39ac5055b813",
   "metadata": {},
   "outputs": [],
   "source": [
    "#计算rfm数据框中每个数值的四分位数（第25百分位、中位数即第50个百分位、第75个百分位）结果将其存储在quantiles变量中\n",
    "#这个变量是一个DataFrame其中包含这些分位点对应的值\n",
    "quantiles = rfm.quantile(q=[0.25, 0.5, 0.75])\n",
    "\n",
    "def RScore(x):  #参数x，实际上是为了计算R分数\n",
    "    #根据recency值与四分位数的关系给定不同的得分\n",
    "    if x <= quantiles['recency'][0.25]:   #如果x小于等于第一个四分位数\n",
    "        return 1    #则得分为1\n",
    "    elif x <= quantiles['recency'][0.5]:  #如果x介于第一个四分位数和第二个四分位数之间\n",
    "        return 2   #则得分为2\n",
    "    elif x <= quantiles['recency'][0.75]:   #如果x介于第二个四分位数和第三个四分位数之间\n",
    "        return 3   #则得分为3\n",
    "    else:\n",
    "        return 4   #否则得分为4\n",
    "\n",
    "def FMScore(x, col):   #该函数接收两个参数，用来计算F或M分数\n",
    "    #函数根据x与指定列col的四分位数的关系来分配分数\n",
    "    if x <= quantiles[col][0.25]:   #如果x小于等于第一个四分位数\n",
    "        return 4\n",
    "    elif x <= quantiles[col][0.5]:   #如果x介于第一个四分位数和第二个四分位数之间\n",
    "        return 3\n",
    "    elif x <= quantiles[col][0.75]:    #如果x介于第二个四分位数和第三个四分位数之间\n",
    "        return 2\n",
    "    else:\n",
    "        return 1\n",
    "\n",
    "rfm['R'] = rfm['recency'].apply(RScore)   #对rfm数据框中的recency列应用RScore函数，并将结果保存到新列R中\n",
    "#对rfm数据框中的frequancy列应用FMScore函数，并将结果保存到新列F中  使用lambda表达式来传递frequancy作为col参数给FMScore函数\n",
    "rfm['F'] = rfm['frequancy'].apply(lambda x: FMScore(x, 'frequancy'))\n",
    "#对rfm数据框中的monetary列应用FMScore函数，并将结果保存到新列M中  使用lambda表达式来传递monetary作为col参数给FMScore函数\n",
    "rfm['M'] = rfm['monetary'].apply(lambda x: FMScore(x, 'monetary'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "5e20686a-1552-4da1-93d0-3390078129fc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "   user_id  recency  frequancy  monetary  R  F  M\n",
      "0     4913        1       1742         6  1  1  3\n",
      "1     6118        1        117         1  1  4  4\n",
      "2     7528        5        214         6  4  4  3\n",
      "3     7591        1        859        21  1  2  1\n",
      "4    12645        1        268         8  1  4  2\n"
     ]
    }
   ],
   "source": [
    "print(rfm.head())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d8dc88be-cafb-4ea9-b4e9-e9f626ea6aea",
   "metadata": {},
   "source": [
    "- 基于提供的RFM分析结果，我们可以对每个用户的行为和交易状态进行操作与解释：\n",
    "## 针对以上的数据，画出折线图和水平柱形图，以不同的维度进行分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "5d910f1b-525b-435a-827d-53e462d66c4f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "   user_id  recency  frequancy  monetary  R  F  M\n",
      "0     4913        1       1742         6  1  1  3\n",
      "1     6118        1        117         1  1  4  4\n",
      "2     7528        5        214         6  4  4  3\n",
      "3     7591        1        859        21  1  2  1\n",
      "4    12645        1        268         8  1  4  2\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'D:\\\\jupyter\\\\淘宝用户购物行为数据分析\\\\rfm_monetary_chart.html'"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from pyecharts.charts import Line,Bar\n",
    "from pyecharts.globals import ThemeType\n",
    "import pyecharts.options as opts  #加载配置项模块\n",
    "from pyecharts.globals import JsCode\n",
    "import pandas as pd\n",
    "\n",
    "#将 时间列转换为datetime类型，方便在网页中显示\n",
    "data['time'] = pd.to_datetime(data['time'])\n",
    "\n",
    "#获取最新日期\n",
    "laster_date = data['time'].max() + pd.Timedelta(days=1)\n",
    "\n",
    "#计算 R、F、M\n",
    "data['recency'] = (laster_date - data.groupby('user_id')['time'].transform('max')).dt.days\n",
    "data['frequancy'] = data.groupby('user_id')['time'].transform('count')\n",
    "data['monetary'] = (data['behavior_type'] == '购买').astype(int)\n",
    "data['monetary'] = data.groupby('user_id')['monetary'].transform('sum')\n",
    "\n",
    "#聚合函数以获得每个用户的 R、F、M值\n",
    "rfm = data.groupby('user_id').agg({\n",
    "    'recency': 'min',\n",
    "    'frequancy': 'max',\n",
    "    'monetary': 'max'\n",
    "}).reset_index()\n",
    "\n",
    "def RScore(x):  #参数x，实际上是为了计算R分数\n",
    "    #根据recency值与四分位数的关系给定不同的得分\n",
    "    if x <= quantiles['recency'][0.25]:   #如果x小于等于第一个四分位数\n",
    "        return 1    #则得分为1\n",
    "    elif x <= quantiles['recency'][0.5]:  #如果x介于第一个四分位数和第二个四分位数之间\n",
    "        return 2   #则得分为2\n",
    "    elif x <= quantiles['recency'][0.75]:   #如果x介于第二个四分位数和第三个四分位数之间\n",
    "        return 3   #则得分为3\n",
    "    else:\n",
    "        return 4   #否则得分为4\n",
    "\n",
    "def FMScore(x, col):   #该函数接收两个参数，用来计算F或M分数\n",
    "    #函数根据x与指定列col的四分位数的关系来分配分数\n",
    "    if x <= quantiles[col][0.25]:   #如果x小于等于第一个四分位数\n",
    "        return 4\n",
    "    elif x <= quantiles[col][0.5]:   #如果x介于第一个四分位数和第二个四分位数之间\n",
    "        return 3\n",
    "    elif x <= quantiles[col][0.75]:    #如果x介于第二个四分位数和第三个四分位数之间\n",
    "        return 2\n",
    "    else:\n",
    "        return 1\n",
    "        \n",
    "#为每个用户计算 R、F、M分数\n",
    "rfm['R'] = rfm['recency'].apply(RScore)   #对rfm数据框中的recency列应用RScore函数，并将结果保存到新列R中\n",
    "#对rfm数据框中的frequancy列应用FMScore函数，并将结果保存到新列F中  使用lambda表达式来传递frequancy作为col参数给FMScore函数\n",
    "rfm['F'] = rfm['frequancy'].apply(lambda x: FMScore(x, 'frequancy'))\n",
    "#对rfm数据框中的monetary列应用FMScore函数，并将结果保存到新列M中  使用lambda表达式来传递monetary作为col参数给FMScore函数\n",
    "rfm['M'] = rfm['monetary'].apply(lambda x: FMScore(x, 'monetary'))\n",
    "\n",
    "#打印前几行数据验证\n",
    "print(rfm.head())\n",
    "\n",
    "#创建折线图\n",
    "def create_line_chart(rfm):\n",
    "    line = (\n",
    "        Line(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))\n",
    "        .add_xaxis(rfm['user_id'].tolist())\n",
    "        .add_yaxis('最近一次购买', rfm['recency'].tolist(), is_smooth=True)\n",
    "        .add_yaxis('购买频率', rfm['frequancy'].tolist(), is_smooth=True)\n",
    "        .add_yaxis('消费金额', rfm['monetary'].tolist(), is_smooth=True)\n",
    "        .set_global_opts(\n",
    "            title_opts=opts.TitleOpts(title='RFM分析 - 折线图'),\n",
    "            xaxis_opts=opts.AxisOpts(name='用户ID'),\n",
    "            yaxis_opts=opts.AxisOpts(name='值'),\n",
    "            visualmap_opts=opts.VisualMapOpts(is_show=False),\n",
    "            \n",
    "            toolbox_opts=opts.ToolboxOpts(is_show=True),  #显示工具箱\n",
    "            tooltip_opts=opts.TooltipOpts(trigger='axis'),\n",
    "            datazoom_opts=[opts.DataZoomOpts()],  #数据区域缩放配置项\n",
    "        )\n",
    "    )\n",
    "    return line\n",
    "\n",
    "#创建水平柱形图\n",
    "def create_bar_chart(rfm, dimension, dimension_name):\n",
    "    bar = (\n",
    "        Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))\n",
    "        .add_xaxis(rfm[dimension].unique().tolist())\n",
    "        .add_yaxis(\"计数\", rfm[dimension].value_counts().sort_index().tolist(), category_gap=\"50%\")\n",
    "        .reversal_axis()\n",
    "        .set_series_opts(label_opts=opts.LabelOpts(position=\"right\"))\n",
    "        .set_global_opts(\n",
    "            title_opts=opts.TitleOpts(title=f\"RFM分析 = {dimension_name} 柱状图\"),\n",
    "            yaxis_opts=opts.AxisOpts(name=\"用户ID\"),\n",
    "            xaxis_opts=opts.AxisOpts(name=\"计数\")\n",
    "        )\n",
    "    )\n",
    "    return bar\n",
    "\n",
    "#使用函数创建图表\n",
    "line_chart = create_line_chart(rfm)\n",
    "bar_recency = create_bar_chart(rfm, 'R', '最近一次购买')\n",
    "bar_frequency = create_bar_chart(rfm, 'F', '购买频率')\n",
    "bar_monetary = create_bar_chart(rfm, 'M', '消费金额')\n",
    "#渲染\n",
    "line_chart.render('rfm_line_chart.html')\n",
    "bar_recency.render('rfm_recency_chart.html')\n",
    "bar_frequency.render('rfm_frequency_chart.html')\n",
    "bar_monetary.render('rfm_monetary_chart.html')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
